IntegrateBackends
Django integration
Authenticate via Olympus in a Django backend
Use django-allauth with the generic OpenID Connect provider.
Setup
pip install django-allauth[socialaccount]settings.py:
INSTALLED_APPS = [
# ...
'allauth',
'allauth.account',
'allauth.socialaccount',
'allauth.socialaccount.providers.openid_connect',
]
SITE_ID = 1
AUTHENTICATION_BACKENDS = [
'django.contrib.auth.backends.ModelBackend',
'allauth.account.auth_backends.AuthenticationBackend',
]
SOCIALACCOUNT_PROVIDERS = {
'openid_connect': {
'APPS': [{
'provider_id': 'olympus',
'name': 'Olympus',
'client_id': os.environ['OLYMPUS_CLIENT_ID'],
'secret': os.environ['OLYMPUS_CLIENT_SECRET'],
'settings': {
'server_url': os.environ['OLYMPUS_ISSUER'],
},
}],
}
}URLs
urlpatterns = [
# ...
path('accounts/', include('allauth.urls')),
]django-allauth provides /accounts/oidc/olympus/login/ to start the flow and /accounts/oidc/olympus/login/callback/ for the callback.
Configure these as the OAuth2 client redirect URI in Athena.
In views
from django.contrib.auth.decorators import login_required
@login_required
def dashboard(request):
user = request.user
# user.email, user.username, etc.
return render(request, 'dashboard.html', {'user': user})REST API (DRF)
For API endpoints consumed by SPAs/mobile:
# settings.py
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': [
'rest_framework.authentication.SessionAuthentication',
'myapp.auth.OlympusTokenAuthentication',
],
}# myapp/auth.py
from rest_framework import authentication, exceptions
import requests
class OlympusTokenAuthentication(authentication.BaseAuthentication):
def authenticate(self, request):
auth_header = request.META.get('HTTP_AUTHORIZATION')
if not auth_header or not auth_header.startswith('Bearer '):
return None
token = auth_header[7:]
info = requests.post(
f"{settings.OLYMPUS_ISSUER}/admin/oauth2/introspect",
data={'token': token},
auth=(settings.HYDRA_ADMIN_USER, settings.HYDRA_ADMIN_PASS),
).json()
if not info.get('active'):
raise exceptions.AuthenticationFailed('inactive token')
user, _ = User.objects.get_or_create(
username=info['sub'],
defaults={'email': info.get('ext', {}).get('email')}
)
return (user, info)