Django REST Framework SSO
Django REST Framework SSO is an extension built upon DRF and SimpleJWT that enables Single sign-on in a microservice-oriented environment using the JWT standard.
This library provides two types of JWT tokens:
- non-expiring session tokens for your primary login application (aka. "refresh tokens")
- 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 refresh token and access token that will allow subsequent requests to the same server and other server which are connected to it.
Quick start
Add "rest_framework_sso" to your INSTALLED_APPS setting like this:
INSTALLED_APPS = [ ... 'rest_framework_simplejwt', 'rest_framework_sso', ]
Include the session and authorization token URLs:
urlpatterns = [ ... url(r'^sso/', include("rest_framework_sso.urls.jwt")) ]
Override acces token class in SimpleJWT settings:
SIMPLE_JWT = { ... 'AUTH_TOKEN_CLASSES': ('rest_framework_sso.tokens.SSOAccessToken',), }
Add authentications:
'DEFAULT_AUTHENTICATION_CLASSES': [ "rest_framework_sso.authentication.SSOJWTTokenUserAuthentication", "rest_framework_sso.authentication.SSOSessionAuthentication", .... ]
Generate ssl keys for verifying/signing a jwt payload
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 ExampleObtainTokenSerializer(rest_framework_sso.serializers.jwt.SSObtainTokenSerializer): """ Returns a JSON Web Token that can be used for authenticated requests. """
JWT Authentication
In order to configuring jwt token, use SimpleJWT settings.
If you want to add custom claims, just override SSORefreshToken model and write your custom JWT payload fields:
from rest_framework_sso.tokens import SSOAccessToken class CustomSSOAccessToken(SSOAccessToken): def custom_claim(self, claim='new_claim'): self.payload[claim] = 'new_claim_value'
Add it to SimpleJWT settings doing the following:
SIMPLE_JWT = { 'ACCESS_TOKEN_CLASSES': ('otherapp.tokens.CustomSSOAccessToken',), ... }
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 contain the JWT payload data in the request.auth variable. 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
The app settings must be placed inside REST_FRAMEWORK_SSO
- SSO_SERIALIZERS
A set of token serializers for handling token-related manipulations:
* obtain_token - a serializer for crafting a new token * refresh_token - a serializer for renewing an already crafted token * verify_token - a serializer for verifying a token
- ACCESS_TOKEN_CLASS
- A dot path to token class for processing access token
Samples
Settings for the app that signing tokens for any client app:
SIMPLE_JWT = { 'ISSUER': 'authority', 'SUBJECT': 'authority', 'AUDIENCE': ['client', ...], 'ALGORITHM': 'RSA256', 'VERIFYING_KEY': '<private key string>' }
Example settings for project that accepts tokens signed by authority private key for client:
SIMPLE_JWT = { 'ISSUER': 'authority', 'SUBJECT': 'client', 'ALGORITHM': 'RSA256', 'VERIFYING_KEY': '<public key string>' }
Generating RSA keys
See the gist.