42 lines
1.3 KiB
Python
42 lines
1.3 KiB
Python
"""JWT issuance helpers.
|
|
|
|
``rest_framework_simplejwt`` signs tokens without a ``kid`` header, which forces
|
|
consumers to try every published key and makes rotation impossible. Tokens are
|
|
therefore encoded here with the current key's ``kid`` attached.
|
|
"""
|
|
|
|
import jwt
|
|
from django.conf import settings
|
|
from rest_framework_simplejwt.exceptions import TokenError
|
|
from rest_framework_simplejwt.tokens import AccessToken
|
|
|
|
from .keys import signing_jwk
|
|
|
|
|
|
def encode(payload):
|
|
"""Sign ``payload`` with the platform key, tagging the JWS header with ``kid``."""
|
|
jwk = signing_jwk()
|
|
if jwk is None:
|
|
raise TokenError(
|
|
"No signing key is configured. Run `python manage.py "
|
|
"generate_signing_keys` before issuing tokens."
|
|
)
|
|
algorithm = settings.SIMPLE_JWT.get("ALGORITHM", "RS256")
|
|
token = jwt.encode(
|
|
payload,
|
|
settings.SIMPLE_JWT["SIGNING_KEY"],
|
|
algorithm=algorithm,
|
|
headers={"kid": jwk["kid"]},
|
|
)
|
|
return token.decode() if isinstance(token, bytes) else token
|
|
|
|
|
|
class IdentifiedAccessToken(AccessToken):
|
|
"""``AccessToken`` whose encoded form carries the signing key's ``kid``.
|
|
|
|
Decoding is unchanged: an unknown header parameter is ignored by PyJWT, so
|
|
existing ``AccessToken(token)`` reads keep working.
|
|
"""
|
|
|
|
def __str__(self):
|
|
return encode(self.payload) |