opened
gomnet
username_0
Hi,

When I try to validate access_token received from "/common/oauth2/v2.0/token" always I get an invalid format error... What do you think I'm missing?

---
#### Document Details

⚠ *Do not edit this section. It is required for docs.microsoft.com ➟ GitHub issue linking.*

* ID: 2471c08b-befe-8e1a-df08-f13e116c231e
* Version Independent ID: 0d827d33-2906-6352-9398-13863def9354
* Content: [Microsoft identity platform access tokens reference](https://docs.microsoft.com/en-us/azure/active-directory/develop/access-tokens#feedback)
* Content Source: [articles/active-directory/develop/access-tokens.md](https://github.com/Microsoft/azure-docs/blob/master/articles/active-directory/develop/access-tokens.md)
* Service: **active-directory**
* Sub-service: **develop**
* GitHub Login: @rwike77
* Microsoft Alias: **ryanwi**
Access_Token format is invalid
issue
created
gomnet
username_0
btw, id_token is correct, so I suppose some kind of extra encoding is done only to access_token parameter.
comment
created
FrankHu-MSFT
username_1
@username_0 Thanks for your feedback! We will investigate and update as appropriate.
comment
created
SaurabhSharma-MSFT
username_2
@username_0 can you please provide a code snippet with the request parameters for which you are getting this error.
comment
created
zakibenz
username_3
+1
comment
created
zakibenz
username_3
I am running into the same issue (I can validate Id_token sgnature but not access_token).
Here is my code:


`import base64
import jwt
from cryptography.hazmat.primitives.asymmetric.rsa import RSAPublicNumbers
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import serialization


def ensure_bytes(key):
    if isinstance(key, str):
        key = key.encode('utf-8')
    return key


def decode_value(val):
    decoded = base64.urlsafe_b64decode(ensure_bytes(val) + b'==')
    return int.from_bytes(decoded, 'big')


def rsa_pem_from_jwk(jwk):
    return RSAPublicNumbers(
        n=decode_value(jwk['n']),
        e=decode_value(jwk['e'])
    ).public_key(default_backend()).public_bytes(
        encoding=serialization.Encoding.PEM,
        format=serialization.PublicFormat.SubjectPublicKeyInfo
    )


# obtain jwks as you wish: configuration file, HTTP GET request to the endpoint returning them;
jwks = {
    "keys": [
        {
            "kty": "RSA",
            "use": "sig",
            "kid": "piVlloQDSMKx...",
            "x5t": "piVlloQDSMKx...",
            "n": "0XhhwpmEpN-jDBapnzhF...",
            "e": "AQAB",
            "x5c": [
                "MIIDBTCCAe2gAwIBAgIQMCJcg...."
            ],
            "issuer": "https://login.microsoftonline.com/{tenant}/v2.0"
        }
    ]
}

# configuration, these can be seen in valid JWTs from Azure B2C:
valid_audiences = ['dd050a67-ebfd-xxx-xxxx-xxxxxxxx'] # id of the application prepared previously

class InvalidAuthorizationToken(Exception):
    def __init__(self, details):
        super().__init__('Invalid authorization token: ' + details)


def get_kid(token):
    headers = jwt.get_unverified_header(token)
    if not headers:
        raise InvalidAuthorizationToken('missing headers')
    try:
        return headers['kid']
    except KeyError:
        raise InvalidAuthorizationToken('missing kid')



def get_jwk(kid):
    for jwk in jwks.get('keys'):
        if jwk.get('kid') == kid:
            return jwk
    raise InvalidAuthorizationToken('kid not recognized')

def get_issuer(kid):
    for jwk in jwks.get('keys'):
        if jwk.get('kid') == kid:
            return jwk.get('issuer')
    raise InvalidAuthorizationToken('kid not recognized')

def get_public_key(token):
    return rsa_pem_from_jwk(get_jwk(get_kid(token)))


def validate_jwt(jwt_to_validate):
    try:
        public_key = get_public_key(jwt_to_validate)
    issuer = get_issuer(kid)


        options = {
            'verify_signature': True,
            'verify_exp': True,  # Skipping expiration date check
            'verify_nbf': False,
            'verify_iat': False,
            'verify_aud': True  # Skipping audience check
        }

        decoded = jwt.decode(jwt_to_validate,
                             public_key,
                             options=options,
                             algorithms=['RS256'],
                             audience=valid_audiences,
                             issuer=issuer)

        # do what you wish with decoded token:
        # if we get here, the JWT is validated
        print(decoded)

    except Exception as ex:
        print('The JWT is not valid!')
        return False
    else:
        return decoded
        print('The JWT is valid!')`
comment
created
zakibenz
username_3
I've checked that I am using right endpoints (v2.0).
I am using the right **jwks_uri**  from metadata url:

https://login.microsoftonline.com/{tenant}/.well-known/openid-configuration?appid=<your-app-id>

I've also checked I am using the right key corresponding to the right **kid**
comment
created
zakibenz
username_3
I resolved my issue by creating a scope.
Now when I ask for an access_token I get one with the right 'audiance' and signature validation works.

What I dont understand is : Why I should add a scope to my app registration to get tokens with right audiance ?
in my case I just need claims in graph.microsoft.com/User.Read scope ?
comment
created
gomnet
username_0
Thanks for the information, could you give me more details about scope?
Which scope exactly I have to add? Could you confirm me the access_token is
JWT format? And are you using common tenant?

Thx so much for sharing your knowledge.
comment
created
zakibenz
username_3
I just created a custom scope in 'Expose API' section.
The created scope will be prefixed with your Application (client) Id and if it is used to issue a token, your application keys will be used to sign your tokens and 'aud' field (for audiance) will be set to your client Id (this is the way you know if your token was signed with your app keys).

The issued token will be a JWT token and the tenant I used is the tenant of my app as I just need to give access to accounts in my organizational directory only.
comment
closed
SaurabhSharma-MSFT
username_2
issue
created
SaurabhSharma-MSFT
username_2
@username_3 Thanks for your sharing your solution.  We will now proceed to close this thread. If there are further questions regarding this matter, please reopen it and we will gladly continue the discussion.
comment
created
PowerOfM
username_4
Perhaps I'm missing something: in order for the signature of the access_token to be valid, a custom scope must be defined? We're developing applications for clients who create their own app registration. So asking them to define a custom scope seems quite cumbersome and even suspicious. 

Is there another way to go about this?
comment