I need to get OAuth2 Access Token from Azure Active Directory. For this, I am using certificate based method. I have uploaded .crt file to Azure AD and got the certificate thumbprint from the Azure AD UI.
Now I am generating JWT token from JWT.io and trying it using postman. But I always get the following error:
"AADSTS700027: Client assertion contains an invalid signature. [Reason - The key was not found., Thumbprint of key used by client"
I am not sure what could be causing this. In JWT.io I am entering Base64 encoded thumbprint of public certificate (which I uploaded on Azure AD) as x5t parameter. This thumbprint I got from Azure portal UI as mentioned above.
In JWT.io I am entering public (crt) and private (key) certificates under "Verify Signature" and can see that the signature has matched.
Please let me know if anyone has any idea about this.
As far as I know, this error is usually caused by the fact that you did not encode the thumbprint correctly. After you obtain the thumbprint, please check your code to ensure that it is properly Base64 encoded.
Check the format of your JWT token at https://jwt.io/, you can refer to this and certificate credentials:
Header
{
"alg": "RS256",
"typ": "JWT",
"x5t": "<Base64 Thumbprint>"
}
Payload
{
"iss": "<clientid>",
"sub": "<clientid>",
"exp": 1570838377 (expiration time),
"jti": "<random unique identifier>",
"aud": "https://<token-endpoint>"
}
Drop your private key in to the bottom verify-er which will sign your JWT in the "Encoded" window.
I found some cases for your reference, I hope it can help you:
https://community.dynamics.com/crm/f/microsoft-dynamics-crm-forum/320069/authentication-to-dynamics-365-using-azure-apps
and
https://github.com/AzureAD/passport-azure-ad/issues/453
I wanted to share with you that I get this exact same error if I request an access token using a new certificate, right after I just added the new certificate to my AAD app via MS Graph (/addKey). If I immediately try again without changing anything, it is successful. It doesn't seem to matter how long I wait before the 1st try, it's like it needs to fail once before the new cert is ready for use. If I upload certs in the GUI, the issue never surfaces.
I know it's not the same issue you're having, but it's worth knowing what else AAD will give this exact error message for.
Related
We've configured Snowflake for Oauth2 using AAD when we retrieve a token the audience, scope, ... are correct.
But when validating using SYSTEM$VERIFY_EXTERNAL_OAUTH_TOKEN
we receive the following error (and no information can be found why this is occuring)
Token Validation finished.{"Validation Result":"Failed","Failure
Reason":"EXTERNAL_OAUTH_JWS_CANT_RETRIEVE_PUBLIC_KEY"}
Has anyone had this error before?
Most likely while creating the security integration,value for Public Key was not extracted from the IdP's certificate and instead, the certificate was entered.
I have set-up an identity server 3 that serves bearer tokens. I then consume that JWT bearer in my api. All is working fine. However, i cannot seem to validate a token in jwt.io debugger. I paste in the valid base64 bearer into the debugger then try and verify the signature by pasting in the contents of the "x5c" from the idserver/.well-known/jwks into the verify signature. this says invalid. what am i doing wrong? owin works fine with app.UseIdentityServerBearerTokenAuthentication(new IdentityServer3.AccessTokenValidation.IdentityServerBearerTokenAuthenticationOptions()
I believe I am missing something with the implicit grant process and access tokens in aws cognito.
To this point:
Have a user pool, with a client app configured for implicit flow and scopes openid, profile, aws.cognito.signin.user.admin
Used a stack overview and the official documentation and older white papers to achieve:
Login process that redirects to aws cognito UI, and back to my app, with tokens and other information in the fragment portion of the URL.
The access_token value parses at jwt.io and signature checks out using the aws jwt tool
Problem:
The recommended step is to "verify that the access token belongs to us" through the tokeninfo api call.
When I attempt to call tokeninfo via javascript code and testing via postman (using: https://api.amazon.com/auth/o2/tokeninfo?access_token=eyJraWQiOiJoVFBa... )
I get the result:
{
"error_description": "The request has an invalid parameter : access_token",
"error": "invalid_token"
}
and an http header:
x-amzn-errortype: InvalidTokenException:http://internal.amazon.com/coral/com.amazon.panda/
Variants I have tried:
I have tried calls directly to the user profile (using Authorization header, and query string and x-amz-access-token header).
I have tried adjust parameter names (error becomes "access_token required" or something like that
I have tried adjusting scopes in the user pool
I have tried adding resource servers (though I am not there yet...)
The redirect after login looks like this:
https://staging.example.com/loginresult.html#id_token=eyJraWQiO<tokenremoved>&access_token=eyJraWQiOiJoVFBa<tokenremoved>&expires_in=3600&token_type=Bearer&state=whateverdevwants
The parsed values of the token (through jwt.io) are:
{
"sub": "5510a27d-ebcb-4883-8680-a66fd0462279",
"token_use": "access",
"scope": "aws.cognito.signin.user.admin openid profile",
"iss": "https://cognito-idp.us-east-1.amazonaws.com/us-east-1_OF5OOfdx0",
"exp": 1519352461,
"iat": 1519348861,
"version": 2,
"jti": "31950a91-e2a5-4060-8c31-977f49802d35",
"client_id": "3iuhnprmod0josge24ogarecfp",
"username": "5510a27d-ebcb-4883-8680-a66fd0462279"
}
Update: As answered below: just don't do this, it is conflating jwt tokens from cognito with whatever "Login With Amazon" was using.
In the example you refer to from Amazon they encode the access token using urllib.quote_plus for example in their PHP example.
Make sure you are URL encoding the access token too in your javascript code with encodeURI.
Also an error may be returned if the token has expired so make sure you verify a newly-minted token. Expiry is 3600 seconds - so make sure the token is less than an hour old.
EDIT
Looks like the documentation for Cognito is very different from the LWA (login with amazon) auth flow. The tokens in the examples you linked to aren't even JWT tokens!
The Cognito documentation here explains how to verify the JWT token.
Checkout the Using ID Tokens and Access Tokens in your Web APIs paragraph.
I have an application registered in Azure AD which uses certificates. I am trying to write a script which would add a new certificate to the application. This can be used to add a new certificate when the existing certificate is going to expire.
I am trying to use AddKey function of Azure AD Graph API. The request body of this api as a parameter 'proof' which is a JWT assertion signed by the existing certificate of the application. The doc says the "aud" claim in JWT should be set to "AAD Graph SPN". Here what is meant by "AAD Graph SPN"?
I tried with a JWT where "aud" was set to "00000002-0000-0000-c000-000000000000". But I am getting the following error,
{
"odata.error": {
"code":"Authorization_RequestDenied",
"message":{
"lang":"en",
"value":"Insufficient privileges to complete the operation."
}
}
}
Any thoughts on this?
I am getting the access token to call the Azure AD Graph API via "Resource Owner Credentials Grant" flow . To get the access token i am using the client_id "1950a258-227b-4e31-a9cf-717495945fc2" (The Well Known Client ID for Azure PowerShell")
My script (For deployment purpose) does something like below,
i) Get the access token as described above and registers a new application in Azure AD with a initial certificate.
ii) When the initial certificate is about to expire it should add a new certificate to the created application.
According to the documentation, you must use a self-signed JWT token to access that API:
As part of the request validation for this service action, a proof of
possession of an existing key is verified before the action can be
performed. The proof is represented by a self-signed JWT token. The
requesting application needs to generate a self-signed JWT token with
the following requirements...
The "Resource Owner Credentials Grant" won't work here in this situation. Instead, use the "Client Credentials Grant":
https://learn.microsoft.com/en-us/azure/active-directory/develop/active-directory-protocols-oauth-service-to-service
The application you want to update should be the Client ID used to get this access token.
The other option is to update the application directly using an PATCH request on the Application Object:
https://msdn.microsoft.com/en-us/library/azure/ad/graph/api/entity-and-complex-type-reference#application-entity
Using this method, you should be able to update using the method you described above (user credentials and an external Client ID)
Let me know if this helps.
How do I deal with this corrupt response when using Oauth as the login mechanism for my website? I'm implementing Oauth login that will replace the Open ID login that I had previously been using.
I redirect the user to https://accounts.google.com/o/oauth2/auth to request their permission. I'm using the scope email profile openid and the openid.realm of http://subdomain.mysite.example.com
The user accepts the permissions and comes back with a code parameter.
I submit this code parameter to https://accounts.google.com/o/oauth2/token along with my app credentials.
Google sends back a JSON repsonse that includes an access_token and an id_token.
I have to parse the id_token to determine the identify of the user. The token is three base64 encoded sections delimited by periods (.). I split it on periods and look at the middle one which has the "claims" information I'm looking for. The other sections are cryptographic signatures which I ignore since I'm communicating directly with Google over HTTPS.
The claims is supposed to be a JSON object when I decode it, but occasionally it is corrupt. When it is is corrupt, the corruption is always around the open id section.
Here is an example of the access_token (the data here is for my own account):
eyJhbGciOiJSUzI1NiIsImtpZCI6IjM1MzExZDJiMWI2OTQ0NTVkYmY2ZmE4YTUyYTNmNzZkYTUwMDUwM2IifQ.eyJpc3MiOiJhY2NvdW50cy5nb29nbGUuY29tIiwic3ViIjoiMTAwNDkwNzU0NjA0MjY0MTgxNzg0IiwiYXpwIjoiMTAwMzUzNDIwNDkwOC1nM3Z1bDAzb2phbGRkZjN0NmxlMjdvMG9xZWhzazNmNy5hcHBzLmdvb2dsZXVzZXJjb250ZW50LmNvbSIsImVtYWlsIjoic3Rvc3Rlcm1AZ21haWwuY29tIiwiYXRfaGFzaCI6Im1kalkxdTlEQ2VXcEVwWC15N0h3enciLCJlbWFpbF92ZXJpZmllZCI6dHJ1ZSwiYXVkIjoiMTAwMzUzNDIwNDkwOC1nM3Z1bDAzb2phbGRkZjN0NmxlMjdvMG9xZWhzazNmNy5hcHBzLmdvb2dsZXVzZXJjb250ZW50LmNvbSIsIm9wZW5pZF9pZCI6Imh0dHBzOi8vd3d3Lmdvb2dsZS5jb20vYWNjb3VudHMvbzgvaWQ_aWQ9QUl0T2F3bDR4NlZXVE1fbHVWSGhwb1VqTlE1VE56c3BzcjFqTF8wIiwiaWF0IjoxNDA1NDI2MDQ0LCJleHAiOjE0MDU0Mjk5NDR9.UWEZZOhJfg5CGEHd9FNnYg__tiAysmMABk_Q0wSGaq6jbXPwe91J4JXwSgpwVBa09St7zjLRL-ajswMe-qooBe_ItzaEhXPgfc6pKWBSIWeqaj-PM2lyXECWQTAwxsm8xtBXCtjJUfyyjp3ciA95g7Rz9JHPTGDJRMywkFhb-fc
Then here is the extracted middle "claims" section:
eyJpc3MiOiJhY2NvdW50cy5nb29nbGUuY29tIiwic3ViIjoiMTAwNDkwNzU0NjA0MjY0MTgxNzg0IiwiYXpwIjoiMTAwMzUzNDIwNDkwOC1nM3Z1bDAzb2phbGRkZjN0NmxlMjdvMG9xZWhzazNmNy5hcHBzLmdvb2dsZXVzZXJjb250ZW50LmNvbSIsImVtYWlsIjoic3Rvc3Rlcm1AZ21haWwuY29tIiwiYXRfaGFzaCI6Im1kalkxdTlEQ2VXcEVwWC15N0h3enciLCJlbWFpbF92ZXJpZmllZCI6dHJ1ZSwiYXVkIjoiMTAwMzUzNDIwNDkwOC1nM3Z1bDAzb2phbGRkZjN0NmxlMjdvMG9xZWhzazNmNy5hcHBzLmdvb2dsZXVzZXJjb250ZW50LmNvbSIsIm9wZW5pZF9pZCI6Imh0dHBzOi8vd3d3Lmdvb2dsZS5jb20vYWNjb3VudHMvbzgvaWQ_aWQ9QUl0T2F3bDR4NlZXVE1fbHVWSGhwb1VqTlE1VE56c3BzcjFqTF8wIiwiaWF0IjoxNDA1NDI2MDQ0LCJleHAiOjE0MDU0Mjk5NDR9
Which Base64 decodes to a corrupt JSON object. Here is a snippet from the corrupt section:
"openid_id":"https://www.google.com/accounts/o8/idYPR]Ø]Û
I originally thought it was a character encoding issue. I'm using UTF-8 when decoding the base64 to a string. I've tried using other encodings and all appear corrupt. I'm thinking it is not character encoding related also because the corruption is happening in a URL which should all be ASCII.
This bug only appears to happen with some accounts, but when it happens, it happens consistently for that account. Even logging out of Google completely does not solve the problem.
I first saw this problem when I deleted my test app in the Google Developer Console and created a new app with new credentials. My Google account was fine with the old app, but has the problem under the new app.
Am I doing something wrong, or does Google have a bug?
You might not be decoding the token properly.
I went to https://developers.google.com/wallet/digital/docs/jwtdecoder and pasted the token you provided:
eyJhbGciOiJSUzI1NiIsImtpZCI6IjM1MzExZDJiMWI2OTQ0NTVkYmY2ZmE4YTUyYTNmNzZkYTUwMDUwM2IifQ.eyJpc3MiOiJhY2NvdW50cy5nb29nbGUuY29tIiwic3ViIjoiMTAwNDkwNzU0NjA0MjY0MTgxNzg0IiwiYXpwIjoiMTAwMzUzNDIwNDkwOC1nM3Z1bDAzb2phbGRkZjN0NmxlMjdvMG9xZWhzazNmNy5hcHBzLmdvb2dsZXVzZXJjb250ZW50LmNvbSIsImVtYWlsIjoic3Rvc3Rlcm1AZ21haWwuY29tIiwiYXRfaGFzaCI6Im1kalkxdTlEQ2VXcEVwWC15N0h3enciLCJlbWFpbF92ZXJpZmllZCI6dHJ1ZSwiYXVkIjoiMTAwMzUzNDIwNDkwOC1nM3Z1bDAzb2phbGRkZjN0NmxlMjdvMG9xZWhzazNmNy5hcHBzLmdvb2dsZXVzZXJjb250ZW50LmNvbSIsIm9wZW5pZF9pZCI6Imh0dHBzOi8vd3d3Lmdvb2dsZS5jb20vYWNjb3VudHMvbzgvaWQ_aWQ9QUl0T2F3bDR4NlZXVE1fbHVWSGhwb1VqTlE1VE56c3BzcjFqTF8wIiwiaWF0IjoxNDA1NDI2MDQ0LCJleHAiOjE0MDU0Mjk5NDR9.UWEZZOhJfg5CGEHd9FNnYg__tiAysmMABk_Q0wSGaq6jbXPwe91J4JXwSgpwVBa09St7zjLRL-ajswMe-qooBe_ItzaEhXPgfc6pKWBSIWeqaj-PM2lyXECWQTAwxsm8xtBXCtjJUfyyjp3ciA95g7Rz9JHPTGDJRMywkFhb-fc
was decoded to:
Header:
{ "alg": "RS256", "kid": "35311d2b1b694455dbf6fa8a52a3f76da500503b" }
Claims:
{
"exp": 1405429944,
"sub": "100490754604264181784",
"iss": "accounts.google.com",
"email_verified": true,
"at_hash": "mdjY1u9DCeWpEpX-y7Hwzw",
"openid_id": "https:\/\/www.google.com\/accounts\/o8\/id?id=AItOawl4x6VWTM_luVHhpoUjNQ5TNzspsr1jL_0",
"azp": "1003534204908-g3vul03ojalddf3t6le27o0oqehsk3f7.apps.googleusercontent.com",
"iat": 1405426044,
"email": "REMOVED_TO_AVOID_SPAM",
"aud": "1003534204908-g3vul03ojalddf3t6le27o0oqehsk3f7.apps.googleusercontent.com"
}
So your OpenID looks to be https://www.google.com/accounts/o8/id?id=AItOawl4x6VWTM_luVHhpoUjNQ5TNzspsr1jL_0".
If you use Java you can get the same result using Apache commons Base64 class:
String str = "eyJpc3MiOiJhY2NvdW50cy5nb29nbGUuY29tIiwic3ViIjoiMTAwNDkwNzU0NjA0MjY0MTgxNzg0IiwiYXpwIjoiMTAwMzUzNDIwNDkwOC1nM3Z1bDAzb2phbGRkZjN0NmxlMjdvMG9xZWhzazNmNy5hcHBzLmdvb2dsZXVzZXJjb250ZW50LmNvbSIsImVtYWlsIjoic3Rvc3Rlcm1AZ21haWwuY29tIiwiYXRfaGFzaCI6Im1kalkxdTlEQ2VXcEVwWC15N0h3enciLCJlbWFpbF92ZXJpZmllZCI6dHJ1ZSwiYXVkIjoiMTAwMzUzNDIwNDkwOC1nM3Z1bDAzb2phbGRkZjN0NmxlMjdvMG9xZWhzazNmNy5hcHBzLmdvb2dsZXVzZXJjb250ZW50LmNvbSIsIm9wZW5pZF9pZCI6Imh0dHBzOi8vd3d3Lmdvb2dsZS5jb20vYWNjb3VudHMvbzgvaWQ_aWQ9QUl0T2F3bDR4NlZXVE1fbHVWSGhwb1VqTlE1VE56c3BzcjFqTF8wIiwiaWF0IjoxNDA1NDI2MDQ0LCJleHAiOjE0MDU0Mjk5NDR9";
System.out.println(new String(org.apache.commons.codec.binary.Base64.decodeBase64(str.getBytes())));
To solve the problem, I had to switch from com.google.appengine.repackaged.com.google.common.util.Base64 to org.apache.commons.codec.binary.Base64;