WamISSO Documentation

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.
See also: Overview · Laravel · Python (Flask)