django-oauth-toolkit
django-oauth-toolkit copied to clipboard
private_key_jwt support?
Plan on using client_credentials grant type, but I don't see where private_key_jwt supported. Pretty critical to maintain good security with server to server implementations. Please advise. Thanks.
If you are toking about jwt-bearer as client assertion type you can use the following code using extended oauth2 validator. Standard: https://www.rfc-editor.org/rfc/rfc7523#section-2.2
I haven't prepared a PR but you can use this code:
public_key is defined in a extended application model:
class MyApplication(oauth2_provider_models.AbstractApplication):
public_key = models.TextField('Public key (Jwt Grant)', blank=True, null=True)
JWT_BEARER_CLIENT_ASSERTION_TYPE = 'urn:ietf:params:oauth:client-assertion-type:jwt-bearer'
class MyOauth2Validator(oauth2_validators.OAuth2Validator):
def _authenticate_jwt_bearer(self, request: common.Request):
try:
client_id = request.client_id
decoded_body = dict(request.decoded_body or [])
client_assertion_type = decoded_body['client_assertion_type']
client_assertion = decoded_body['client_assertion']
except (AttributeError, KeyError):
return False
if client_assertion_type != JWT_BEARER_CLIENT_ASSERTION_TYPE:
return False
if self._load_application(client_id, request) is None:
log.debug('Failed basic auth: Application %s does not exist' % client_id) # noqa: S001
return False
public_key = _get_public_key(request.client.public_key)
if public_key is None:
return False
try:
assertion = jwt.decode(
client_assertion,
key=public_key,
algorithms=['RS256', 'RS384', 'RS512'],
audience='https://www.bitstamp.net',
)
if client_id != assertion.get('iss') or client_id != assertion.get('sub'):
return False
return True
except jwt.PyJWTError as e:
log.info('Client error in token decode. %s.', e)
return False
def authenticate_client(self, request, *args, **kwargs):
authenticated = super().authenticate_client(request, *args, **kwargs)
if not authenticated:
authenticated = self._authenticate_jwt_bearer(request)
return authenticated
def _get_public_key(key):
# type: (str) -> typing.Any
if key is not None and key.startswith('-----BEGIN CERTIFICATE-----'):
key = x509.load_pem_x509_certificate(key.encode('utf-8'))
return key.public_key()
return key
@LiteWait what do you mean by private_key_jwt support? can you link to defining OAuth or OIDC specification?