{"id":16421808,"url":"https://github.com/peppelinux/django-jwtconnect-auth","last_synced_at":"2026-04-20T14:05:25.965Z","repository":{"id":143289823,"uuid":"295438883","full_name":"peppelinux/django-jwtconnect-auth","owner":"peppelinux","description":"A Django JWT Authentication Backend on top of JWTConnect.io 's CryptoJWT and OidcMsg.","archived":false,"fork":false,"pushed_at":"2020-09-18T11:05:44.000Z","size":353,"stargazers_count":2,"open_issues_count":1,"forks_count":0,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-02-24T17:50:16.077Z","etag":null,"topics":["django","django-rest-auth","jws","jwt","jwt-auth","jwt-authentication","jwt-token","jwt-tokens"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/peppelinux.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-09-14T14:18:55.000Z","updated_at":"2021-02-22T12:11:36.000Z","dependencies_parsed_at":"2023-05-11T04:15:27.073Z","dependency_job_id":null,"html_url":"https://github.com/peppelinux/django-jwtconnect-auth","commit_stats":{"total_commits":22,"total_committers":1,"mean_commits":22.0,"dds":0.0,"last_synced_commit":"80e1c381e4c8c4b344cb6c4948c1d63b5ee2301e"},"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/peppelinux/django-jwtconnect-auth","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/peppelinux%2Fdjango-jwtconnect-auth","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/peppelinux%2Fdjango-jwtconnect-auth/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/peppelinux%2Fdjango-jwtconnect-auth/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/peppelinux%2Fdjango-jwtconnect-auth/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/peppelinux","download_url":"https://codeload.github.com/peppelinux/django-jwtconnect-auth/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/peppelinux%2Fdjango-jwtconnect-auth/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32050454,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-20T11:35:06.609Z","status":"ssl_error","status_checked_at":"2026-04-20T11:34:48.899Z","response_time":94,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["django","django-rest-auth","jws","jwt","jwt-auth","jwt-authentication","jwt-token","jwt-tokens"],"created_at":"2024-10-11T07:34:52.141Z","updated_at":"2026-04-20T14:05:25.950Z","avatar_url":"https://github.com/peppelinux.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# django-jwtconnect-auth\nA Django JWT Authentication Backend built on top of JWTConnect.io, [CryptoJWT](https://cryptojwt.readthedocs.io/) and [OidcMsg](https://oidcmsg.readthedocs.io/).\n\nThis application made simple building a JWT based authentication system, with less as possibile endpoints involved.\nIts birth is due to a desire for simplification in cases where a customized system is required for the granting of authorizations to access resources. It comes with the bare minimum, it could be useful as a basis also for the production of *OAuth2 AS* and *OIDC Providers*, it would just need to add specific endpoints and further attributes in the construction of the JWT.\n\nThe main goal for this application is to __provide a secure standard for JWT management and not to offer a OAuth2 or OIDC compliant server__. These can be implemented on top of this app as well. This application also show us how to deal with [OidcMsg](https://oidcmsg.readthedocs.io/) and [CryptoJWT](https://cryptojwt.readthedocs.io/) in a totally free way.\n\nAt this time and as it is, jwtconnect-auth can be adopted for the following scopes:\n\n- Third-party applications can have Access tokens and renew these, via Rest API (Django Rest framework)\n- Creation of token after a user have been logged in, in cases where third-party Single SignOn systems were involved. There wouldn't be any direct submission of credentials from Application to jwtconnect-auth to obtain a token.\n\n# Specifications and common endpoints\n\n- Tokens could be also relased with an authentication web resource where to submit username and password, mind that this would be disabled in the field of SSO infrastructures as SAML2, you can decide how and why you should do this.\n- Token creation is triggered once, independently by what kind of External Authentication happens, a django signal creates the token for authenticated users if this doesn't exist yet (signal should be enabled in your setup).\n  The release mechanism can be completely customized, you can decide how and where the release of token to the Apps would happen, implementing it in your own.\n- Tokens can be refreshed via POST method: `/token/refresh` by default, but it's customizable in the `urls.py` of your project folder.\n- A user can have multiple active tokens or one at time (configurable in general `settings`).\n- TokenIntrospection endpoint would let third-party applications to get additional informations about a token.\n\n  \n# Token Introspection\n\nThe requestor must be authenticated, a valid access token must bresent in its http request headers.\nParams supported: token, jti.\n\nExample:\n  ````\n  curl -H 'Content-type: application/json; indent=4' -H \"Accept: application/json\" -d '{\"jti\":\"cd9db7ca7560149c543b08a8b8f03393eeb979e9c26d877f66c1fbca23a8554d\"}' -X POST http://127.0.0.1:8000/token/introspection -H \"Authorization: Bearer $ACCESS_TOKEN\"\n  ````\n\n![Alt text](gallery/introspection.png) \n\n\n# Token Refresh\n  \nParams supported: token -\u003e must be a valid refresh token.\n\nExample:\n  ````\n  curl -H 'Content-type: application/json; indent=4' -H \"Accept: application/json\" -d '{\"token\":\"$REFRESH_TOKEN}' -X POST http://127.0.0.1:8000/token/refresh\n  ````\n \n![Alt text](gallery/refresh.png) \n\n\n# Demo project\n\nIn `example/` folder we have an example project usable as a demo.\n\n````\npip install -r requirements.txt\ncd example\n./manage.py migrate\n./manage.py createsuperuser\n./manage.py runserver\n````\n\n# Setup\n\nInstall this application and all its dependency\n````\npip install git+https://github.com/peppelinux/django-jwtconnect-auth.git\n````\n\nAdd it in `settings.INSTALLED_APPS`:\n````\nINSTALLED_APPS = [\n    ...\n\n    'rest_framework',\n    'jwtconnect_auth',\n\n    ...\n]\n````\n\nMinimum parameters involved to get it to work, see a list of these in `jwtconnect_auth/settings.py`\n````\n# JWTCONNECT SETTINGS\nJWTAUTH_KEY  = import_private_rsa_key_from_file('certs/private.key')\nJWTAUTH_CERT = import_public_key_from_cert_file('certs/public.cert')\nJWTAUTH_ISSUER = 'http://localhost:8000'\n````\n\n## Settings\n\nIn `settings.REST_FRAMEWORK` add Authentication class:\n\n````\nREST_FRAMEWORK = {\n\n    'DEFAULT_AUTHENTICATION_CLASSES': [\n        # jwtconnect auth\n        'jwtconnect_auth.authentication.JWTConnectAuthBearer'\n    ]\n}\n````\n\nCreate RSA certificates in your desidered folders:\n````\nopenssl req -nodes -new -x509 -days 3650 -keyout certs/private.key -out certs/public.cert -subj '/CN=your.own.fqdn.com'\n````\n\n#### Settings Parameters\nComplete list.\n\n````\nfrom cryptojwt.jwk.x509 import import_public_key_from_cert_file\nfrom cryptojwt.jwk.rsa import import_private_rsa_key_from_file\n\n# in seconds\nJWTAUTH_ACCESS_TOKEN_LIFETIME = 1800\nJWTAUTH_REFRESH_TOKEN_LIFETIME = 3600\n\nJWTAUTH_ALLOW_REFRESH = True\nJWTAUTH_UPDATE_LAST_LOGIN = True\n\n# Signature features (see cryptojwt documentation)\n\n# if symmetric: discouraged, please mind the security!\nJWTAUTH_ALGORITHM: 'HS256'\nJWTAUTH_KEY = 'thatsecret'\n\n# if asymmetric\nJWTAUTH_ALGORITHM: 'RS256'\nJWTAUTH_KEY  = import_private_rsa_key_from_file('certs/private.key')\nJWTAUTH_CERT = import_public_key_from_cert_file('certs/public.cert')\n\nJWTAUTH_ISSUER = 'ISSUER - service or provider name'\nJWTAUTH_AUTH_HEADER_TYPES = ('Bearer',)\n\n# include which one you want to pass in the token, the missing will be omitted\nJWTAUTH_CLAIMS_MAP = dict(username = 'username',\n                          first_name = 'given_name',\n                          last_name = 'family_name',\n                          email = 'email')\n\n# indicates if a user can have multiple and concurrent active tokens or only one per time (the last overwrite the older)\nJWTAUTH_MULTIPLE_TOKENS = True\n````\n\n# Tests\n\n````\ncd example\n./manage.py test jwtconnect_auth -v 2\n````\n\nCoverage\n\n````\ncd example\npip install coverage\ncoverage erase\ncoverage run ./manage.py test jwtconnect_auth\ncoverage report -m\n````\n\n# API\n\nPlaying with internals\n\n````\nfrom jwtconnect_auth.jwks import *\nfrom django.contrib.auth import get_user_model\nuser = get_user_model().objects.first()\ndata = JWTConnectAuthTokenBuilder.build(user)\ndata\n\njwts = JWTConnectAuthTokenBuilder.create(data)\n````\n\ndata would be something like:\n````\n({'iat': 1600125663,\n  'iss': 'http://localhost:8000',\n  'sub': '80327042b96b9f1c00d9d04db816e84af4e3616db1d0694b13ab86f49fd251bf',\n  'jti': '5069631f237a6711b950ab965666ae465aca4e7b5daa0ae783fac2e11e148fce',\n  'ttype': 'T',\n  'exp': 1600127463,\n  'username': 'wert',\n  'given_name': '',\n  'family_name': '',\n  'email': ''},\n {'iat': 1600125663,\n  'iss': 'http://localhost:8000',\n  'sub': '80327042b96b9f1c00d9d04db816e84af4e3616db1d0694b13ab86f49fd251bf',\n  'ttype': 'R',\n  'jti': '064dd076bcafa7fba9a2055452d8b7d48eb5327f1aa4dffc8d1be5ffd8bb3b12',\n  'exp': 1600129263})\n````\n\nJWTs would be something like:\n````\n  \"access_token\": \"eyJhbGciOiJSUzI1NiJ9.eyJpYXQiOiAxNjAwMzMwNzk1LCAiaXNzIjogImh0dHA6Ly9sb2NhbGhvc3Q6ODAwMCIsICJzdWIiOiAiYmIzNjI1NDgzYmQ0M2NjZGZhODk0ZWI3YTg4MTg3ZDNlZTI2MWQ0ZmRkMmIwMDFhNzMyMGY0YTRmMzk2YmM1YyIsICJqdGkiOiAiYmJhNWI3YmM2YzMzMjhlNmFjMGM2MDYxMTdjNGFkMTIxNzdiMzljMjc4ZDM0OTE3NTQ5NzljYWRhMGRkMmRhNSIsICJ0dHlwZSI6ICJUIiwgImV4cCI6IDE2MDAzMzI1OTUsICJ1c2VybmFtZSI6ICJjaXJvIiwgImVtYWlsIjogInRoYXRtYWlsQGluZ29hbGxhLm9yZyJ9.d_ZPZdBasemDuDEMZTkU_eCpCsrhrAvVobLdxkLZBI5E0-FLA4MJC66HxoXStUI2TXBwvqpKrcD_Je_5TNlqg7YuA-B9nUqkDPTIvUl1IwY4v4Ijyu-Trq6HNDkfnr4tYRKJqFIPzQGYnrcR_ox3-IdZQk1mveZzwwXWTnAyyA5G872jeTT0XOb8s2GBwUyS8ppT_ZstrxjpcGRcQ8YYIB7g4NAY33_BmeEFxsEbLmNrYYKR8PjskkCgiqOqtuhTaCBfBJJJ4BU07jBfUI0CjuJaLsKdAYA_HKlrH0B_hxbhF-LNvv88MtcuKD-FA76Ua3Ye8JQQqWXtCI6jYWbjPQ\",\n  \"refresh_token\": \"eyJhbGciOiJSUzI1NiJ9.eyJpYXQiOiAxNjAwMzMwNzk1LCAiaXNzIjogImh0dHA6Ly9sb2NhbGhvc3Q6ODAwMCIsICJzdWIiOiAiYmIzNjI1NDgzYmQ0M2NjZGZhODk0ZWI3YTg4MTg3ZDNlZTI2MWQ0ZmRkMmIwMDFhNzMyMGY0YTRmMzk2YmM1YyIsICJ0dHlwZSI6ICJSIiwgImp0aSI6ICI0ZWY3ZTM5MDIxN2I4NDE3MzUyYjA1MTM3NGQ1MGQwN2U1ZTEyYWI4OWE2ZTkzZmJhN2NlNTFhMDE3ODZlMjZjIiwgImV4cCI6IDE2MDAzMzQzOTV9.PLfPFCSqxtoVyufYNTJuD60ElW-2YG7cyKXJX6WMzgHeaYA96zCelscnfiK_RCuLkr6woZ_mbcZtI24ZIaR4pG_JE7onxCP8wg3oZE0yMGKcv5GXnWeAjx5mE3eBiIhvrZMH6Vn19prNyAuQ8Y5JCJUUeJ4QZiuYYk3TZAKAXAPoNaU1e__f7qHDmkfdBEZ7LliX5bQxkviAdfXS5VbX5CAgB1gOlgbaO4FTbtOpKoVn4YV0gfD_eV_E004JnmpGiOc5-yapE1w3-tTKTkxnfggD6TZOCm8oIZv2k3vkc1pTBIrts1inNg7EEukPdYvX6GFba3fe4FIY-p_6HBmG4A\",\n  \"token_type\": \"bearer\",\n  \"expires_in\": 1800\n\n````\n\n#### JWT implementation\n\n[OidcMsg](https://oidcmsg.readthedocs.io/) is the underlying library for doing this.\n\n````\nfrom oidcmsg.message import Message\n\ndata = dict(\n            # many attributes\n            given_name='peppe',\n            family_name='tarantino',\n\n            exp=None, # timestamp representing the datetime of expiration\n            iat=None, # timestamp representing the datetime of creation\n            aud=None, # JWT is intended for, to which service have been released\n            iss=None, # issuer, the django backend service identifier\n            sid=None, # session id\n            sub=None, # subject, no longher than 256bytes. Opaque string that univocally identifies the user\n            jti=None  # unique identifier for this token\n            )\n\nmsg = Message(**data)\n\n# JWT representation (without signature)\nmsg.to_dict()\nmsg.to_jwt()\n\n````\n\n### JWS implementation\n\n[CryptoJWT](https://cryptojwt.readthedocs.io/) is the underlying library for doing this.\n\n*Symmetric*\n````\nfrom cryptojwt.jwk.hmac import SYMKey\n\nkeys = [SYMKey(key=\"A1B2C3D4HAHAHAHAHAHAHAHA\")]\njws = msg.to_jwt(keys, \"HS256\")\n\n# signed JWT\njws\n````\n\n*Asymmetric*\n\nBuild JWKs\n````\nfrom cryptojwt.jwk.rsa import new_rsa_key\nrsa_key = new_rsa_key()\njwk = rsa_key.serialize(private=True)\n\n# public\nrsa_key.serialize()\n````\n\nImport JWKs\n````\nfrom cryptojwt.jwk.jwk import key_from_jwk_dict\n_key = key_from_jwk_dict(jwk_dict)\n````\n\nImport PEM\n````\nfrom cryptojwt.jwk.x509 import import_public_key_from_cert_file\nfrom cryptojwt.jwk.rsa import import_private_rsa_key_from_file\n\npublic = import_public_key_from_cert_file('certs/public.cert')\nprivate = import_private_rsa_key_from_file('certs/private.key')\n\n# and then ...\nfrom cryptojwt.jwk.rsa import RSAKey\nrsa_key = RSAKey(priv_key=private)\n````\n\nExport JWKs to PEM\n````\nfrom cryptojwt.tools import keyconv\n\n# public\nkeyconv.export_jwk(rsa_key)\n\n# private\nkeyconv.export_jwk(rsa_key, private=True)\n\n````\n\nSign a JWT\n````\nfrom cryptojwt.jwk.rsa import RSAKey\n\nkeys = [RSAKey(**jwk)]\njws = msg.to_jwt(keys, \"RS256\")\n\n# signed jws\njws\n````\n\n*Message to Signed JWT*\n\n````\n# with symmetric keys\njwt = msg.to_jwt(keys, \"HS256\")\n\n# with asymmetric keys\njwt = msg.to_jwt(keys, \"RS256\")\n````\n\n*JWT signature verification*\n````\nfrom cryptojwt.key_jar import KeyJar\n\nkey_jar = KeyJar()\n\n# \"\" means default, you can always point to a issuer identifier\nkey_jar.import_jwks(jwk, issuer_id=\"\")\n\nrecv = Message().from_jwt(jws, keyjar=key_jar, key=keys)\nrecv.verify() # must return True\n\nrecv.to_dict()\n````\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpeppelinux%2Fdjango-jwtconnect-auth","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpeppelinux%2Fdjango-jwtconnect-auth","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpeppelinux%2Fdjango-jwtconnect-auth/lists"}