I created a multi-tenant app on Azure Portal and sending request to get token with application's client Id. I am using the following URL to get token on Microsoft Azure AD
https://login.microsoftonline.com/common/oauth2/v2.0/authorize
Sending a get request with parameters client_id={clientId}&response_type=token&scope=user.read+openid+profile+offline_access
However it is returning an access_token on given call-back url
http://localhost:8082/my-callback-url#access_token=EwCIA8l6BAAU6k7%2bXVQzkGyMv7VHB/h4cHbJYRAAATb8xtkaxI5xsVkWM6etOevj7ADopBYP1/hj%2bUz%2bf1ZXH4lpykHkES1XBRBDNRDWwdqAA%2brO2tFlMygiuusVx1EJKvqeV0rPPaNDNX9azpWGzS45BN6WmXKcxzX623enNYJOdo%2bYyTtaMipFapvABOsjHve1nVwfq9zqpmcldnIhXBeGefdQsgqmBNjeAyAbWzifLNtdz6Ybxnbt8nMY5adb82Z8tsfddfDdjrqk%2bu%2b85%2bxKXO9Xop3wdRvrVC9FM46RniA6H3NUKjOMTJAsX4IQLjGjXM4eq9o95lmSzF3zgFOXI1rYwkDRVsFsLOgP8tx0occDcuVPQgMalXR6JREDZgAACIJRWLYJGUcWWAKPx26NmroNGG1xEkPB1kLeGk0Hf8324YZs2InsGvQBFUMU4XzGGNdj0s5rLYKK2ictDstHV1daM241F1M5FiaX1qCgdRXneR9uPzUsSIBOzPJtT1dD4k%2bDxp6Nr4hEnDPlymp5X0SR4v5vUA3aRhnsvmEzBVQDKR7cFvT7NSqVHSr/tTv/epdx81qgJcd6S6xF8oaMc7mn76jgU4YBn8jXYnTfGhUvhNZ8RJyyl71AqZrGr7JS2kStselZUgjavLqc9DdQD9cwPSWu1ketKmGgCjt6lVB3nlaw8Wxq%2by2/YhPznTRFD2wj/vzDOdTzCcZ9mJV%2bKMGcXYQqBiGE0MF8%2bWA1EKSXniT5UiegTfJkvnsgtx6G6sdV0rzFM7Xa9d/dHNDfyV5oGedZtJXE1WCUrEIUZZm/HNhhQyh0WSG0gWm3vOY7NAs13vey9lcIQ6Fllu6W/Ty3HE4llFp/9a3lNcujmlxsCASFUOX6R54xPJMt1ipF5lh5uyZCPoUda46UsrCDnNRg0dhuoSVwJMDHzDbs4NXhX4nhTOze/9koz6p5Ao4DtJ20LqmcylZDoLxUhXIU5vvnBYpiHwanBt2E/rG%2bqVEQbRy/v9fhi0chY0XPzldIm/Lz2l0%2b0MpJ/4l53f9YTRLdEMD8X8Umi35ZvpK9arAqgdRkx4/oWG9m8sxOMY2eASetiAJaU8yjtETgHpBGJTXbDVDpNA1s5NGc9QC%2brcSnGDV0BKIDYxBISR8TiJQVUaPqbNU1Mj3kGyQFnfS0jS83VGVfFCZ4cHkhDq/awLh2JrR0Ag%3d%3d&token_type=bearer&expires_in=3600&scope=User.Read%20openid%20profile
How can I validate this access token? or how can I get a JWT token instead?
Your scopes are user.read+openid+profile+offline_access.
That first one is a Microsoft Graph API scope.
It's actually short-hand for https://graph.microsoft.com/user.read.
So you will get an access token that is meant for Microsoft Graph API.
The other scopes you defined affect the id token (openid, profile) or get you a refresh token (offline_access).
This means you cannot and should not validate the token.
Only Microsoft Graph API should be validating this token, since the token is meant for it.
If you want an access token for your API, you need to use a scope defined in the API's app registration (Expose an API section).
Related
I'm coding a project composed by an SPA and an API.
On the SPA, I have a button to link Google or Microsoft accounts to the user's account.
The API can whenever it wants call google/microsoft apis.
I've succeeded with google using the Authorization code flow:
From the SPA redirecting the user to https://accounts.google.com/o/oauth2/v2/auth with query parameters response_type=code and access_type=offline
Send the returned code to the API
The API call https://oauth2.googleapis.com/token to get an access_token and a refresh_token
Tokens are saved in the database, and can be used whenever the API wants.
==============
Microsoft has a similar authorization flow (https://learn.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-auth-code-flow) but I can't use the authorization_code retrieved from an SPA into the API because of CORS policies.
I'm not using PKCE codes because tokens are retrieved from the API that use client_id and client_secret.
=============
Am I missing something ? Is it even possible to get an authorization_code from an SPA and use it to generate access_tokens and refresh_tokens from an external API ?
Thank you so much, sorry for my english !
In the SPA, many authorization servers and identity providers do not support CORS requests, in such case, your option is to use the Azure AD Implicit grant flow rather than the auth code flow, you can get the access token directly via the /authorize endpoint. This flow does not provide refresh tokens, so your app must be prepared to refresh these tokens periodically.
Reference - Microsoft identity platform and Implicit grant flow
Trying to set up Azure AD OAuth client credentials grant flow for my web api. I'm following the document in https://learn.microsoft.com/en-us/azure/active-directory/develop/v1-oauth2-client-creds-grant-flow. I have to expose my API to a 3rd party. I've created the APP in Azure AD (this is for the client that is requesting my API), generated the secrets and was able to get a response from oauth2/token endpoint. My questions are below:
What is the best way to validate the token? Is it by passing the JWT
(bearer token) as a HTTP header to my API, and then using the SDK to
validate the token
(System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler)? I'm using
C#.
What is the significance of Azure AD -> App Registrations -> "My
API App" -> under Manage, Expose an API? It has an option to
"Authorize client applications". How could I use this feature to
conditionally block and approve the client applications?
I will have to share the secret, client id and the App Id Uri with the 3rd party for them to generate the token and I will validate the token when I receive it.
You're on the right track.
This answer, Azure AD OAuth client credentials grant flow with Web API AuthorizeAttribute Roles, will walk you through one way to do this, using the roles claim in the token to authorize the call.
You will need to:
define roles
create an App registration for each 3rd party
assign their application to your desired roles
You can then use the AuthorizeAttribute to map which roles can execute which controllers/actions, like so:
[Authorize(Roles = "Reader,Requester,Editor,Approver,Administrator")]
Token validation
Once you complete token obtaining flow, you receive a JWT bearer access token. From token consuming end (your service), you need to perform a JWT validation. This is done by validating JWT signature and Claims. One of the most important claim you validate is the audience (aud) claim which must be the identifier (ex:- your service's URL, an ID) unique to token receiving service. Where you register this ? That's your second question.
Please read through MS's guide on token validation which explains key points - Microsoft identity platform access tokens
Service registration
This is where you register valid token receivable endpoints (ex:- your api app). If you check your token request, you provide resource parameter which must match to registered identifier. This allows Azure to validate the token request and issue an access token the mentioned resource. You find this as aud claim in the token. Hope you got the connection now.
App secret
No, only the token obtaining party require the client credentials. Your API or any token consuming party does not need the secret. They only require a valid access token and token signing certificate details. certificate details are exposed at jwks_uri in openid-configuration endpoint.
I am new to OAuth and I am working on app identity/client credential work flow using OAuth. Basically there will be a client application calling the API using the client app's app id. The API will trust whoever have the access to the client app.
The understand I have for the implementation is that:
register client app to Azure AD
put the app id of the client app into the API
enable OAuth request so the client app is able to receive access token from AAD
use the access token to call the API
But my confusion is the relationship between the web app's app id and the access token. I know we have to put the client's app id into the API so the API can somehow recognize the client app. How does the API know the access token is from that specific app id? How does it work exactly?
The app id also named client id, it represents a client application which makes protected resource requests on behalf of the resource owner.
The client application authenticates the resource owner and obtains its authorization, then the authorization server will issue the access token to the client application.
For more details about the relationship, you could see the Azure Active Directory developer glossary.
Update:
For example, I use the client credential flow to get the access token for MS Graph API. Then I decode it in https://jwt.io/ . You will find the claims "aud": "https://graph.microsoft.com/", "appid": "xxxxxx", "app_displayname": "joywebapp2", for more details, see Claims in access tokens.
The you use the access token to call MS Graph API, it will know the access token is from that specific client app as you asked.
There is a dedicated protocol/validation mechanism for this. Once token is received at resource server (ex:- API as in your example), it can perform a token introspection to identify the context of the token. OAuth 2.0 Token Introspection define how the introspection request should be build and what to expect from response.
This specification defines a protocol that allows authorized
protected resources to query the authorization server to determine
the set of metadata for a given token that was presented to them by
an OAuth 2.0 client.
Read through the introspection response section to identify what sort of data it will return. Client ID is also some valid claim.
Now there is an alternative approach too. This is what Azure AD has adopted. Azure Active Directory use JWT formatted access tokens.
Azure Active Directory access tokens
Access tokens enable clients to securely call APIs protected by Azure. Azure Active Directory (Azure AD) access tokens are JWTs, Base64 encoded JSON objects signed by Azure. Clients should treat access tokens as opaque strings, as the contents of the token are intended for the resource only.
JWT tokens are self contained, which mean the holder/receiver can validate the integrity of the token and verify claims valid. Go through token validation section which explain the complete process. One key claim you must focus is the audience claim. This denote the intended audience of JWT and can have multiple values (array).
I already made the authentication flow with the Microsoft Graph/Azure AD authentication. Once I get the authenticated user's token I store them in his cookies. To validate the user's token I call the Microsft Graph API resource /me. This does not seem a good approach because basically everytime time a client does a request to my API, he is basically doing 2 requests because my API requests Azure AD for validation.
Is this a good flow?
No, it isn't.
Your front-end should acquire an access token for your API, which the API can verify using its digital signature.
The token will contain some info about the user as well as the app that acquired it.
The way in which the front-end acquires the token depends on the type of application.
Front-end single page apps use implicit grant flow for example.
Do note that you have to specifically ask for an access token for your API.
As long as your back-end is then configured with standard JWT Bearer authentication,
all is handled.
This is done by specifying the authority as your Azure AD tenant (or the common endpoint if it's multi-tenant),
and the standard bits for JWT authentication should download the public keys from Azure AD's metadata endpoint, which it can then use to verify validity of any access token it receives.
You do not have to validate tokens for an api that's not yours (issued to your AppId Uri).
For example, Graph validates the tokens that are sent to it (issued for "https://graph.microsoft.com).
If you build and register in Azure AD an Api of your own (say AppIdUri="https://myapi.mydomain.com"), your clients will request and receive access tokens with aud claim set to "https://myapi.mydomain.com".
The clients themselves don't need to validate the access token issued for your Api But your Api, when it receives those access tokens, has to validate them. The validations, among other things will validate the access token was issued to "https://myapi.mydomain.com".
Try out this sample, to get a good understanding around concepts of token validation.
I have an ASP.NET Core WebApi which uses Azure AD Bearer Tokens (passed by the Frontend, acquired using adal.js).
Currently, we are using the Azure AD Graph API and everything works fine.
As recommended by Microsoft, we would like to migrate from Azure AD Graph API to Microsoft Graph.
I changed the audience from https://graph.windows.net to https://graph.microsoft.com both in the API and Frontend. I can successfully acquire a token, which looks almost the same as the old one when decrypted in jwt.io, but when I pass it to the API I get:
Bearer was not authenticated. Failure message: IDX10503: Signature validation failed. Keys tried: 'Microsoft.IdentityModel.Tokens.X509SecurityKey
Did I miss something? As far as I know, it should be possible to sign in using the Microsoft Graph, right?
If I understood correctly, you have configured your API audience as the MS Graph API audience.
You should not do this.
Firstly MS Graph API access tokens are bit special and you should not try to validate them,
secondly because your API is not MS Graph API.
Your front-end should acquire an access token for your API.
This requires you to configure your API audience as either its client id or Application ID URI (or both).
Azure AD allows the front-end to acquire the token using either of those.
The API can then exchange that for an MS Graph API token using the On-Behalf-Of flow.