Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes14kdownloads
token.py219 linesDownload Raw Back to rfc9068
1import time2from typing import List3from typing import Optional4from typing import Union5 6from authlib.common.security import generate_token7from authlib.jose import jwt8from authlib.oauth2.rfc6750.token import BearerTokenGenerator9 10 11class JWTBearerTokenGenerator(BearerTokenGenerator):12    '''A JWT formatted access token generator.13 14    :param issuer: The issuer identifier. Will appear in the JWT ``iss`` claim.15 16    :param \\*\\*kwargs: Other parameters are inherited from17        :class:`~authlib.oauth2.rfc6750.token.BearerTokenGenerator`.18 19    This token generator can be registered into the authorization server::20 21        class MyJWTBearerTokenGenerator(JWTBearerTokenGenerator):22            def get_jwks(self):23                ...24 25            def get_extra_claims(self, client, grant_type, user, scope):26                ...27 28        authorization_server.register_token_generator(29            'default',30            MyJWTBearerTokenGenerator(issuer='https://authorization-server.example.org'),31        )32    '''33 34    def __init__(35        self,36        issuer,37        alg='RS256',38        refresh_token_generator=None,39        expires_generator=None,40    ):41        super().__init__(42            self.access_token_generator, refresh_token_generator, expires_generator43        )44        self.issuer = issuer45        self.alg = alg46 47    def get_jwks(self):48        '''Return the JWKs that will be used to sign the JWT access token.49        Developers MUST re-implement this method::50 51            def get_jwks(self):52                return load_jwks("jwks.json")53        '''54        raise NotImplementedError()55 56    def get_extra_claims(self, client, grant_type, user, scope):57        '''Return extra claims to add in the JWT access token. Developers MAY58        re-implement this method to add identity claims like the ones in59        :ref:`specs/oidc` ID Token, or any other arbitrary claims::60 61            def get_extra_claims(self, client, grant_type, user, scope):62                return generate_user_info(user, scope)63        '''64        return {}65 66    def get_audiences(self, client, user, scope) -> Union[str, List[str]]:67        '''Return the audience for the token. By default this simply returns68        the client ID. Developpers MAY re-implement this method to add extra69        audiences::70 71            def get_audiences(self, client, user, scope):72                return [73                    client.get_client_id(),74                    resource_server.get_id(),75                ]76        '''77        return client.get_client_id()78 79    def get_acr(self, user) -> Optional[str]:80        '''Authentication Context Class Reference.81        Returns a user-defined case sensitive string indicating the class of82        authentication the used performed. Token audience may refuse to give access to83        some resources if some ACR criterias are not met.84        :ref:`specs/oidc` defines one special value: ``0`` means that the user85        authentication did not respect `ISO29115`_ level 1, and will be refused monetary86        operations. Developers MAY re-implement this method::87 88            def get_acr(self, user):89                if user.insecure_session():90                    return '0'91                return 'urn:mace:incommon:iap:silver'92 93        .. _ISO29115: https://www.iso.org/standard/45138.html94        '''95        return None96 97    def get_auth_time(self, user) -> Optional[int]:98        '''User authentication time.99        Time when the End-User authentication occurred. Its value is a JSON number100        representing the number of seconds from 1970-01-01T0:0:0Z as measured in UTC101        until the date/time. Developers MAY re-implement this method::102 103            def get_auth_time(self, user):104                return datetime.timestamp(user.get_auth_time())105        '''106        return None107 108    def get_amr(self, user) -> Optional[List[str]]:109        '''Authentication Methods References.110        Defined by :ref:`specs/oidc` as an option list of user-defined case-sensitive111        strings indication which authentication methods have been used to authenticate112        the user. Developers MAY re-implement this method::113 114            def get_amr(self, user):115                return ['2FA'] if user.has_2fa_enabled() else []116        '''117        return None118 119    def get_jti(self, client, grant_type, user, scope) -> str:120        '''JWT ID.121        Create an unique identifier for the token. Developers MAY re-implement122        this method::123 124            def get_jti(self, client, grant_type, user scope):125                return generate_random_string(16)126        '''127        return generate_token(16)128 129    def access_token_generator(self, client, grant_type, user, scope):130        now = int(time.time())131        expires_in = now + self._get_expires_in(client, grant_type)132 133        token_data = {134            'iss': self.issuer,135            'exp': expires_in,136            'client_id': client.get_client_id(),137            'iat': now,138            'jti': self.get_jti(client, grant_type, user, scope),139            'scope': scope,140        }141 142        # In cases of access tokens obtained through grants where a resource owner is143        # involved, such as the authorization code grant, the value of 'sub' SHOULD144        # correspond to the subject identifier of the resource owner.145 146        if user:147            token_data['sub'] = user.get_user_id()148 149        # In cases of access tokens obtained through grants where no resource owner is150        # involved, such as the client credentials grant, the value of 'sub' SHOULD151        # correspond to an identifier the authorization server uses to indicate the152        # client application.153 154        else:155            token_data['sub'] = client.get_client_id()156 157        # If the request includes a 'resource' parameter (as defined in [RFC8707]), the158        # resulting JWT access token 'aud' claim SHOULD have the same value as the159        # 'resource' parameter in the request.160 161        # TODO: Implement this with RFC8707162        if False:  # pragma: no cover163            ...164 165        # If the request does not include a 'resource' parameter, the authorization166        # server MUST use a default resource indicator in the 'aud' claim. If a 'scope'167        # parameter is present in the request, the authorization server SHOULD use it to168        # infer the value of the default resource indicator to be used in the 'aud'169        # claim. The mechanism through which scopes are associated with default resource170        # indicator values is outside the scope of this specification.171 172        else:173            token_data['aud'] = self.get_audiences(client, user, scope)174 175        # If the values in the 'scope' parameter refer to different default resource176        # indicator values, the authorization server SHOULD reject the request with177        # 'invalid_scope' as described in Section 4.1.2.1 of [RFC6749].178        # TODO: Implement this with RFC8707179 180        if auth_time := self.get_auth_time(user):181            token_data['auth_time'] = auth_time182 183        # The meaning and processing of acr Claim Values is out of scope for this184        # specification.185 186        if acr := self.get_acr(user):187            token_data['acr'] = acr188 189        # The definition of particular values to be used in the amr Claim is beyond the190        # scope of this specification.191 192        if amr := self.get_amr(user):193            token_data['amr'] = amr194 195        # Authorization servers MAY return arbitrary attributes not defined in any196        # existing specification, as long as the corresponding claim names are collision197        # resistant or the access tokens are meant to be used only within a private198        # subsystem. Please refer to Sections 4.2 and 4.3 of [RFC7519] for details.199 200        token_data.update(self.get_extra_claims(client, grant_type, user, scope))201 202        # This specification registers the 'application/at+jwt' media type, which can203        # be used to indicate that the content is a JWT access token. JWT access tokens204        # MUST include this media type in the 'typ' header parameter to explicitly205        # declare that the JWT represents an access token complying with this profile.206        # Per the definition of 'typ' in Section 4.1.9 of [RFC7515], it is RECOMMENDED207        # that the 'application/' prefix be omitted. Therefore, the 'typ' value used208        # SHOULD be 'at+jwt'.209 210        header = {'alg': self.alg, 'typ': 'at+jwt'}211 212        access_token = jwt.encode(213            header,214            token_data,215            key=self.get_jwks(),216            check=False,217        )218        return access_token.decode()219 
codekingpro/portable-devtools · Team Ai