I am getting invalid signature while using jwt.io to validate my azure ad access token (will shift to scala code after the manual checking).
I am using curl to generate the access token:
curl -s -X POST https://login.microsoftonline.com/<tenant id>/oauth2/token -d grant_type=password -d username=$username -d password=$pass -d resource=$resID -d client_id=$id -d client_secret=$key
While it is giving me the access token, the response doesnt contain the "Id_token". Not sure why.
I am wrapping the public key from https://login.microsoftonline.com/common/discovery/keys with BEGIN and END certificate. (as mentioned in https://nicksnettravels.builttoroam.com/post/2017/01/24/Verifying-Azure-Active-Directory-JWT-Tokens.aspx)
I am not sure what else is missing.
The decoded header is as follows:
{
"typ": "JWT",
"alg": "RS256",
"x5t": "9FXDpbfMFT2SvQuXh846YTwEIBw",
"kid": "9FXDpbfMFT2SvQuXh846YTwEIBw"
}
Warning: You are invoking a flow which is unsupported, and will be removed in the near future.
The Resource Owner Password Credentials Grant flow (grant_type=password) is not supported in Azure AD with confidential clients (i.e. web app/web API, where there exists a client_secret). If you are confident your scenario requires the Resource Owner flow (very few scenarios actually warrant the risks introduced by this flow), then you should be invoking it with a client_id registered for a native client app (a public client). Alternatively, you should be invoking an interactive sign-in (if you are signing in actual human users), or pursuing the Client Credentials Grant flow (if this is a daemon/unattended service).
You are not getting an ID Token because the flow you've invoked (the OAuth 2.0 Resource Owner Password Credentials Grant flow), does not define any concept of an ID Token, or an id_token response. In other words: you haven't asked for one.
If you add scope=openid to your Authorization Request, you'll be hinting to Azure AD that you're more or less interested in knowing stuff about the person who signed in, and you'll get an unsigned OpenID Connect ID Token in the response.
To https://jwt.io to verify the claims:
Ensure this is a token intended for you. (i.e. don't expect to be able to decode and verify a token that was not intended for you (where "you" are the resource in the Authorization Request, and the aud in the token claims).
Ensure you've selected the correct signing algorithm (RS256).
Ensure you're checking against the key with which the token was signed (use the kid header value from the JWT as a hint).
Ensure the certificate ends in -----END CERTIFICATE----- (I've found jwt.io doesn't care too much about how it starts.
Double-check your copy-pasting, it's easy to accidentally pick up extra characters.
Related
We are using Azure active directory Oauth code flow to authenticate the user.
We got the access_token, id_token and refresh_token using code(got it on redirect URL).
We are using id_token to authorization each request after successful authentication and we can verify JWT using the public key which we got from /discovery/v2.0/keys api.
Now, JWT will expire after 1 hour. so we need to refresh this id_token.
I am refreshing id_token using below cURL
curl --request POST \
--url https://login.microsoftonline.com/{tenant_id}/oauth2/token \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data 'client_id=client%20id&refresh_token=refesh%20token%20&grant_type=refresh_token&client_secret=client_secret&scope=openid
In the response of this API, we got the access_token, refresh_token, id_token, but if you observe id_token, it does not contain JWT signature (the third part of JWT), without signature we can not verify JWT
We can not find any document reference why id_token is not having a signature part.
Is there any other way to refresh id_token?
Is there any workaround if id_token can not be refreshed?
In some cases an Id token may be returned without a signature, especially if it is acquired through a back-channel with a client secret.
You already are getting the token through an encrypted channel, from the authority.
If someone was able to inject something there, they would be able to direct your app's requests for OpenID metadata as well, replacing the signing keys your app expects.
Thus the signature would not add much value here.
In addition, you won't send the Id token to any API as Id tokens should not be used for authorization.
That's what access tokens are for :)
The OpenID Connect spec has this to say: https://openid.net/specs/openid-connect-core-1_0.html#IDTokenValidation
If the ID Token is received via direct communication between the Client and the Token Endpoint (which it is in this flow), the TLS server validation MAY be used to validate the issuer in place of checking the token signature. The Client MUST validate the signature of all other ID Tokens according to JWS [JWS] using the algorithm specified in the JWT alg Header Parameter. The Client MUST use the keys provided by the Issuer.
But then, interestingly mentions this as well: https://openid.net/specs/openid-connect-core-1_0.html#IDToken
ID Tokens MUST be signed using JWS and optionally both signed and then encrypted using JWS and JWE respectively, thereby providing authentication, integrity, non-repudiation, and optionally, confidentiality, per Section 16.14. If the ID Token is encrypted, it MUST be signed then encrypted, with the result being a Nested JWT, as defined in [JWT]. ID Tokens MUST NOT use none as the alg value unless the Response Type used returns no ID Token from the Authorization Endpoint (such as when using the Authorization Code Flow) and the Client explicitly requested the use of none at Registration time.
So.. it could be that Azure AD is not compliant with spec?
EDIT: The v1 endpoint of Azure AD is not compliant in this regard. The newer v2 endpoint is fully OpenID Connect compliant.
We generated JWT using docusign given private key and validated by Docusign public key in jwt.io site. It generated valid signature.
Using same signature we called Docusign demo server for access token
POST https://account-d.docusign.com/oauth/token
with
grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer
assertion=Signature generated
but getting error "Invalid Grant".
What could be the possible reason? If signature is already verified in jwt.io with public key, Docusign should accept the assertion value.
As documented, you also need to supply the following claims:
iss--The integration key (also known as client ID) of the application.
sub--The user ID of the user to be impersonated.
iat--The DateTime when the JWT was issued, in Unix epoch format.
exp--The DateTime when the JWT assertion will expire, in Unix epoch format. Use 1 hour after iat or less.
aud--domain name of the authentication service instance to be used. For demo environments, use account-d.docusign.com For production environments, use account.docusign.com. Note: Do not include https:// in the aud value!
scope--The scopes being requested. For the JWT bearer grant, the requested scope should be signature.
See the docs and also see the DocuSign JWT code examples, the repos named eg-01-*
Ask a new question if you'd like further help.
I have ADB2C built-in policies working. From this, I authenticate my end users and generate JWT tokens to call APIs through APIM, configured with OpenId Connect. I'm setting up right now custom policies (IEF), thanks to the starter kit but it seems not working properly in parallel.
With built-in policies, everything is OK. But when I try to use tokens generated with IEF, even if all the claims are the same, I always got the error 401 "Authorization has been denied for this request."
After a quick look on the generated token, I saw that the key to sign the token is not the same as for built-in generated tokens.
It is certainly where the error comes from. Indeed, when setting up custom policies, we need to create "policy keys" to sign and encrypt tokens. And by default, it is generated, so different from the built-in ones. But I don't know how to fix this!
Note that I really need to have the same signature and encryption keys for both built-in and custom policies because in APIM I can only use 1 metadata URI for OpenId Connect configuration and 1 configuation URL in section within API operation validation policy.
Note also that I didn't find a way to retrieve the current encryption key (used by built-in policies) for refresh tokens. The problem is the same...
Thanks for your help!
Here is a valid token header including the signature key:
{
"typ": "JWT",
"alg": "RS256",
"kid": "X5eXk4xyojNFum1kl2Ytv8dlNP4-c57dO6QGTVBwaNk"
}
Currently, the kid generated by my policy key is "6jQvK3Cr-pdfMP9ozewO3dnmizxxx_toYfjEnxVpJFs"
When I try to upload the same key as I can find by looking at the metadata URI https://mydomain/tenantId/discovery/v2.0/keys?p=a_ief_policy_name, it is properly uploaded
{
keys: [
{
kid: "X5eXk4xyojNFum1kl2Ytv8dlNP4-c57dO6QGTVBwaNk",
nbf: 1493763266,
use: "sig",
kty: "RSA",
e: "AQAB",
n: "tVKUtcx_n9rt[...]VTVSR0hiXudFlfQ2rOhPlpObmku68lXw-7V-P7jwrQRFfQVXw"
}
]
}
But when getting the response of a sign in request I got the error :
AADB2C90085: The service has encountered an internal error. Please reauthenticate and try again.
The OIDC authorize endpoint includes the user flow or custom policy name. So if you are trying to authorize both using the same URL, that could be the cause of your issue.
See here:
https://learn.microsoft.com/en-us/azure/active-directory-b2c/openid-connect
The authorize endpoint is based on the following format:
https://{tenant}.b2clogin.com/{tenant}.onmicrosoft.com/{policy}/oauth2/v2.0/authorize
Since the policy name is included in the URL, which means it would be different for the user flow vs the custom policy.
I am making OAuth 2.0 auth code authentication flow with multi-tenant application.
Here is my authorize url:
https://login.microsoftonline.com/common/oauth2/v2.0/authorize?client_id=my_id&prompt=consent&redirect_uri=http%3A%2F%2Flocalhost%3A3000%2Fauthorize&response_type=code&scope=openid+offline_access&state=17
It goes fine and I receive auth_code. Then I make request with this auth_code to token_url and receive a lot of information, like:
token_type
scope
id_token
access_token
refresh_token
expires_at
ext_expires_in
Seems fine to me, but when I make request on API with access_token like:
https://management.azure.com/subscriptions/my_sub_id/locations?api-version=2016-06-01
with headers:
Content-Type:
- application/json
Authorization:
- Bearer EwBQA8l6BAAURSN/FHlDW5xN74t6GzbtsBBeBUYAAV1IHgHb4dOWblzfd/YsSuFicAMDYbua17QivnAT9/pIaeKAg3uKsK5VGqWLzjMOUQrCpd7R1RAM6RkzI0u8e4rpO7DISG7qLso5H5+U1jb+38/j1urcwlXMMxhy83ZXmdpkLXpZV+vcOV...
It responds with 401 error
body:
encoding: UTF-8
string: '{"error":{"code":"InvalidAuthenticationToken","message":"The access token is invalid."}}'
To be honest I think something wrong with my access_token. It seems not like JWT for me. Documentation says it looks like:
"access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsIng1dCEV1Q..."
But my access_token looks like:
"access_token": "EwBYA8l6BAAURSN/FHlDW5xN74t6GzbtsBBeBUYAAZDe7JE/MPLoAi+Fr+1Xxq5eBe5N9l8Q+c4QjkY5PGEzRnBpPe7+v6h+PLdh1cceBQx+/JsB2QCrYSCt7x/zGsQAhwoY/"
Is it fine?
Here is my permissions for application:
Permissions
The main issue you have here is that you have only asked for an access token for the scopes openid offline_access. The resulting access token will be for Microsoft Graph (https://graph.microsoft.com), not for the Azure REST API (https://management.azure.com).
To indicate you would like a token for a given API, the scope parameter in your authorization request should include the delegated permission you would like the app to have for the API. In the case of Azure REST API, there's only one delegated permission: user_impersonation. The identifier URI for the Azure REST API is https://management.azure.com, so the scope value you want to use is:
openid offline_access https://management.azure.com/user_impersonation
Two more important notes:
As you've discovered, you will not always be issued an access token as a JWT which you can decode peek at. The format of the access token is an agreement between the service which issued the token (Azure AD or Microsoft Accounts, in this case), and the service for which the token was issued (Microsoft Graph, in this example).
You should not always include prompt=consent. prompt=consent should only be used if you have already tried signing in the user without the user needs to be re-prompted for consent for a new permission.
If you simply include the required scopes in the scopes parameter, the Microsoft Identity platform will take care of figuring out if it needs to prompt for consent or not. If you always include prompt=consent, you will find that many organizations will be blocked from accessing your app, because they've disabled the ability for users to grant consent themselves (and this parameter specifically states that you require the user to be prompted again).
I am stuck with the authentication to use the REST API for getting subscription billing information from Resource Usage API
I would like to get help with how to obtain token for non interactive clients. I chose to use the REST API since azure client seems to not support Resource Usage API.
As the Authorization code grant (interactive clients) describes , I have called the request with my subscription id but token is not returned properly.
[root#visual src]# curl -XPOST https://login.microsoftonline.com/xxxxx/oauth2/token -d ""
{"error":"invalid_request","error_description":"AADSTS90014: The request body must contain the following parameter: 'grant_type'.\r\nTrace ID: 32981285-a021-45c3-8d2f-62db49d2c2f1\r\nCorrelation ID: d88849dd-20f9-462e-9ce9-66b6fde0170e\r\nTimestamp: 2017-03-04 04:06:44Z","error_codes":[90014],"timestamp":"2017-03-04 04:06:44Z","trace_id":"32981285-a021-45c3-8d2f-62db49d2c2f1","correlation_id":"d88849dd-20f9-462e-9ce9-66b6fde0170e"}[root#visual src]#
How can I obtain the token?
A token will not be returned if you don't supply some credentials :)
If you want to do a non-interactive request with client credentials for example, your request must contain (in URL-encoded form format):
grant_type=client_credentials
client_id=your-app-client-id
client_secret=your-app-client-secret
resource=resource-uri-for-api-you-want-the-token-for
The resource URI could be for example https://graph.windows.net/ for the Azure AD Graph API.
You can also get tokens with the password grant if you wish to use a username and password. In that case, you must send:
client_id, client_secret and resource as above
grant_type=password
username=your-username
password=your-password