Django Integration
Connect a Django application to WamISSO using the OAuth 2.0 Authorization Code flow with requests.
Before you start:
Complete developer registration and create an OAuth client in the
developer portal.
Register a redirect URI such as
http://localhost:8001/sso/callback/.
Install dependencies
pip install django requests python-dotenv
Environment variables
SSO_BASE_URL=https://wamisso.rendovations.com
SSO_CLIENT_ID=your-client-id
SSO_CLIENT_SECRET=your-client-secret
SSO_REDIRECT_URI=http://localhost:8001/sso/callback/
Settings
# settings.py
import os
from pathlib import Path
from dotenv import load_dotenv
load_dotenv()
SSO_BASE_URL = os.environ["SSO_BASE_URL"]
SSO_CLIENT_ID = os.environ["SSO_CLIENT_ID"]
SSO_CLIENT_SECRET = os.environ["SSO_CLIENT_SECRET"]
SSO_REDIRECT_URI = os.environ["SSO_REDIRECT_URI"]
SESSION_ENGINE = "django.contrib.sessions.backends.db"
URLs
# myapp/urls.py
from django.urls import path
from . import views
urlpatterns = [
path("login/", views.sso_login, name="sso_login"),
path("sso/callback/", views.sso_callback, name="sso_callback"),
path("logout/", views.sso_logout, name="sso_logout"),
]
Views
# myapp/views.py
import secrets
import requests
from django.conf import settings
from django.contrib.auth import get_user_model, login, logout
from django.shortcuts import redirect
from django.http import HttpResponseBadRequest
User = get_user_model()
def sso_login(request):
state = secrets.token_urlsafe(32)
request.session["oauth_state"] = state
params = {
"client_id": settings.SSO_CLIENT_ID,
"redirect_uri": settings.SSO_REDIRECT_URI,
"response_type": "code",
"scope": "openid profile email",
"state": state,
}
return redirect(f"{settings.SSO_BASE_URL}/oauth/authorize", params=params)
def sso_callback(request):
if request.GET.get("state") != request.session.pop("oauth_state", None):
return HttpResponseBadRequest("Invalid OAuth state")
code = request.GET.get("code")
if not code:
return HttpResponseBadRequest("Missing authorization code")
token_response = requests.post(
f"{settings.SSO_BASE_URL}/oauth/token",
data={
"grant_type": "authorization_code",
"client_id": settings.SSO_CLIENT_ID,
"client_secret": settings.SSO_CLIENT_SECRET,
"redirect_uri": settings.SSO_REDIRECT_URI,
"code": code,
},
headers={"Accept": "application/json"},
timeout=15,
)
token_response.raise_for_status()
tokens = token_response.json()
profile_response = requests.get(
f"{settings.SSO_BASE_URL}/api/user",
headers={
"Accept": "application/json",
"Authorization": f"Bearer {tokens['access_token']}",
},
timeout=15,
)
profile_response.raise_for_status()
profile = profile_response.json()
user, _ = User.objects.update_or_create(
username=profile.get("email") or profile["sub"],
defaults={
"email": profile.get("email", ""),
"first_name": profile.get("name", ""),
},
)
request.session["sso_access_token"] = tokens["access_token"]
login(request, user)
return redirect("/")
def sso_logout(request):
access_token = request.session.pop("sso_access_token", None)
if access_token:
requests.post(
f"{settings.SSO_BASE_URL}/api/sso/logout",
headers={
"Accept": "application/json",
"Authorization": f"Bearer {access_token}",
},
timeout=15,
)
logout(request)
return redirect("/")
Refresh token
def refresh_sso_token(refresh_token: str) -> dict:
response = requests.post(
f"{settings.SSO_BASE_URL}/oauth/token",
data={
"grant_type": "refresh_token",
"refresh_token": refresh_token,
"client_id": settings.SSO_CLIENT_ID,
"client_secret": settings.SSO_CLIENT_SECRET,
},
headers={"Accept": "application/json"},
timeout=15,
)
response.raise_for_status()
return response.json()
Store
client_secret only on the server. Never expose it in templates or browser-side code.