Skip to main content

Django REST Framework SSO

Build

Django REST Framework SSO is an extension to Django REST Framework that enables Single sign-on in a microservice-oriented environment using the JWT standard.

Supports Python 3.11+ and Django 5.2, 6.0, 6.1.

This library provides two types of JWT tokens:

  1. non-expiring session tokens for your primary login application (aka. "refresh tokens")
  2. short-lived authorization tokens for accessing your other apps (these contain permissions given by the primary app)

The client is expected to first login to your primary login application by POSTing an username and password. The client will receive a permanent session token that will allow subsequent requests to the same server be authenticated. These tokens do not contain any permissions/authorization information and cannot be used for SSO into other apps.

Afterwards, the client is expected to obtain and keep updating authorization tokens using the session token. These secondary tokens are short-lived (15mins..1 hour) and contain the permissions that the user has at the time of issuance. These tokens are used to access other services, which then trust the permissions in the JWT payload for the lifetime of the token.

Quick start

  1. Add rest_framework_sso to your INSTALLED_APPS setting:
INSTALLED_APPS = [
    ...
    'rest_framework_sso',
]
  1. Include the session and authorization token URLs:
from rest_framework_sso.views import obtain_session_token, obtain_authorization_token

urlpatterns = [
    ...
    path('session/', obtain_session_token),
    path('authorize/', obtain_authorization_token),
]

Additional data in authorization tokens

For example, you may want to include an account field in your JWT authorization tokens, so that otherapp will know about the user's permissions. To do this, you may need to override the ObtainAuthorizationTokenView and AuthorizationTokenSerializer:

class ObtainAuthorizationTokenView(rest_framework_sso.views.ObtainAuthorizationTokenView):
    """
    Returns a JSON Web Token that can be used for authenticated requests.
    """
    serializer_class = AuthorizationTokenSerializer


class AuthorizationTokenSerializer(serializers.Serializer):
    account = serializers.HyperlinkedRelatedField(
        queryset=Account.objects.all(),
        required=True,
        view_name='api:account-detail',
    )

    class Meta:
        fields = ['account']

Replace the authorization token view in your URL conf:

urlpatterns = [
    path('authorize/', ObtainAuthorizationTokenView.as_view()),
    ...
]

Add the account keyword argument to the create_authorization_payload function:

from rest_framework_sso import claims

def create_authorization_payload(session_token, user, account, **kwargs):
    return {
        claims.TOKEN: claims.TOKEN_AUTHORIZATION,
        claims.SESSION_ID: session_token.pk,
        claims.USER_ID: user.pk,
        claims.EMAIL: user.email,
        'account': account.pk,
    }

You will need to activate this function in the settings:

REST_FRAMEWORK_SSO = {
    'CREATE_AUTHORIZATION_PAYLOAD': 'myapp.authentication.create_authorization_payload',
    ...
}

JWT Authentication

In order to get-or-create User accounts automatically within your microservice apps, you may need to write your custom JWT payload authentication function. It receives the decoded JWTCredentials and returns the user together with the credentials to expose in request.auth (returning only the user is still supported):

from django.contrib.auth import get_user_model
from rest_framework_sso import claims

def authenticate_payload(payload, request=None):
    user_model = get_user_model()
    user, created = user_model.objects.get_or_create(
        service=payload.get(claims.ISSUER),
        external_id=payload.get(claims.USER_ID),
    )
    if not user.is_active:
        raise exceptions.AuthenticationFailed(_('User inactive or deleted.'))
    return user, payload

Enable authenticate_payload function in REST_FRAMEWORK_SSO settings:

REST_FRAMEWORK_SSO = {
    'AUTHENTICATE_PAYLOAD': 'otherapp.authentication.authenticate_payload',
    ...
}

Enable JWT authentication in the REST_FRAMEWORK settings:

REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': (
        'rest_framework_sso.authentication.JWTAuthentication',
        'rest_framework.authentication.SessionAuthentication',
        ...
    ),
    ...
}

Requests that have been successfully authenticated with JWTAuthentication carry a JWTCredentials object in request.auth, with the following attributes:

  • header: the JWT header the token was signed with (alg, kid, ...)
  • payload: the verified JWT claims
  • session_token: the SessionToken the token belongs to, or None when VERIFY_SESSION_TOKEN is disabled

request.auth is also a read-only mapping over the payload, so request.auth.get(claims.USER_ID) works as well. This data can be used in your API views/viewsets to handle permissions, for example:

from rest_framework_sso import claims

class UserViewSet(viewsets.ReadOnlyModelViewSet):
    serializer_class = UserSerializer
    queryset = User.objects.none()

    def get_queryset(self):
        if not request.user.is_authenticated or not request.auth:
            return self.none()
        return User.objects.filter(
            service=request.auth.get(claims.ISSUER),
            external_id=request.auth.get(claims.USER_ID),
        )

Settings

Example settings for project that both issues and validates tokens for myapp and otherapp:

REST_FRAMEWORK_SSO = {
    'CREATE_AUTHORIZATION_PAYLOAD': 'myapp.authentication.create_authorization_payload',
    'IDENTITY': 'myapp',
    'SESSION_AUDIENCE': ['myapp'],
    'AUTHORIZATION_AUDIENCE': ['myapp', 'otherapp'],
    'ACCEPTED_ISSUERS': ['myapp'],
    'KEY_STORE_ROOT': '/srv/myapp/keys',
    'PUBLIC_KEYS': {
        'myapp': ['myapp-20200410.pem', 'myapp-20180101.pem'],  # both private/public key in the same file
    },
    'PRIVATE_KEYS': {
        'myapp': ['myapp-20200410.pem', 'myapp-20180101.pem'],  # both private/public key in the same file
    },
}

Example settings for project that only accepts tokens signed by myapp public key for otherapp:

REST_FRAMEWORK_SSO = {
    'AUTHENTICATE_PAYLOAD': 'otherapp.authentication.authenticate_payload',
    'VERIFY_SESSION_TOKEN': False,
    'IDENTITY': 'otherapp',
    'ACCEPTED_ISSUERS': ['myapp'],
    'KEY_STORE_ROOT': '/srv/otherapp/keys',
    'PUBLIC_KEYS': {
        'myapp': ['myapp-20200410.pem', 'myapp-20180101.pem'],  # only public keys in these files
    },
}

Full list of settings parameters with their defaults:

REST_FRAMEWORK_SSO = {
    'CREATE_SESSION_PAYLOAD': 'rest_framework_sso.utils.create_session_payload',
    'CREATE_AUTHORIZATION_PAYLOAD': 'rest_framework_sso.utils.create_authorization_payload',
    'ENCODE_JWT_TOKEN': 'rest_framework_sso.utils.encode_jwt_token',
    'DECODE_JWT_TOKEN': 'rest_framework_sso.utils.decode_jwt_token',
    'AUTHENTICATE_PAYLOAD': 'rest_framework_sso.utils.authenticate_payload',

    'ENCODE_ALGORITHM': 'RS256',
    'DECODE_ALGORITHMS': None,
    'VERIFY_SIGNATURE': True,
    'VERIFY_EXPIRATION': True,
    'VERIFY_ISSUER': True,
    'VERIFY_AUDIENCE': True,
    'VERIFY_SESSION_TOKEN': True,
    'EXPIRATION_LEEWAY': 0,
    'SESSION_EXPIRATION': None,
    'AUTHORIZATION_EXPIRATION': datetime.timedelta(seconds=300),

    'IDENTITY': None,
    'SESSION_AUDIENCE': None,
    'AUTHORIZATION_AUDIENCE': None,
    'ACCEPTED_ISSUERS': None,
    'KEY_STORE_ROOT': None,
    'PUBLIC_KEYS': {},
    'PRIVATE_KEYS': {},

    'AUTHENTICATE_HEADER': 'JWT',
}

Generating RSA keys

You can use openssl to generate your public/private key pairs:

openssl genpkey -algorithm RSA -out private_key.pem -pkeyopt rsa_keygen_bits:2048
openssl rsa -pubout -in private_key.pem -out public_key.pem
cat private_key.pem public_key.pem > keys/myapp-20180101.pem

Metadata

Release files for djangorestframework-sso 0.8.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for djangorestframework-sso 0.8.0
File Size Uploaded
djangorestframework_sso-0.8.0.tar.gz 57.9 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for djangorestframework-sso 0.8.0
File Interpreter ABI Platform
djangorestframework_sso-0.8.0-py3-none-any.whl Python 3 none any Details

Total release size: 76.5 kB

Release files / djangorestframework_sso-0.8.0.tar.gz

Download URL djangorestframework_sso-0.8.0.tar.gz
Size 57.9 kB
Tags Source
SHA-256 checksum
How to use checksums
d5d2e4c71a56ea697f8da5c3f6da41d5fc4d74c72c84e7aafea470c1a7326161
BLAKE2b-256 checksum
How to use checksums
e2345008c87daef156ab8b0d3f080c114c15314721e91df8542d404ef02bb8b9
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 2, 2026.

Transparency log

Release files / djangorestframework_sso-0.8.0-py3-none-any.whl

Download URL djangorestframework_sso-0.8.0-py3-none-any.whl
Size 18.6 kB
Tags Python 3
SHA-256 checksum
How to use checksums
db10fa30d21cfb5788be975872bf5e6f7d2559b4f498acd78d0f0ec433ccfb22
BLAKE2b-256 checksum
How to use checksums
f861e4919059cc388f325004a1f3eab6a6418f76cb52f1c8a85db72b47479d9d
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 2, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.8.0 This release

2 release files

0.7.0

2 release files

0.6.0

2 release files

0.5.2

2 release files

0.5.1

2 release files

0.5.0

2 release files

0.4.2

2 release files

0.4.1

2 release files

0.4.0

2 release files

0.3.4

2 release files

0.3.3

2 release files

0.3.2

2 release files

0.3.1

2 release files

0.3.0

2 release files

0.2.4

2 release files

0.2.3

2 release files

0.2.2

2 release files

0.2.1

2 release files

0.2.0

2 release files

0.1.0

2 release files

0.0.10

1 release file

0.0.9

1 release file

0.0.8

1 release file

0.0.7

1 release file

0.0.6

1 release file

0.0.5

1 release file

0.0.4

1 release file

0.0.3

1 release file

0.0.2

1 release file

0.0.1

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page