Microsoft Authentication request additional scope with Access Token - azure-active-directory

The Microsoft Authentcation is very complex in my eyes. There are so many flows and stuff going!
So what I'm doing currently is
Get a token for a specific scope using the Authorization code flow. I'm using the following scope: https://admin.services.crm.dynamics.com//user_impersonation (as far as I know I can only request a token for a single scope/audience)
The token works fine. I can access the dynamics admin center with the bearer token I received.
What I'm trying to do now is the following:
I'm trying to access the Microsoft Graph endpoint to read information about the users AAD.
I cannot use the existing token from above, as this one only has the user_importation scope for https://admin.services.crm.dynamics.com/
I have to request another token with the scope user.read
That's where I'm stuck. How can I use the existing access_token to request an additional scope?
I can use the oauth2/v2.0/token endpoint in combination with the refresh token to request a token for another scope (user.read). This works fine, but I don't want to use the refresh token for this, but instead use the access_token. Is this even possible and makes sense?

Is this even possible and makes sense?
No, you could not use access token to get new access token with addition scope.
As you have said, you could use refresh token to request a new access token for another scope. Refresh tokens do not have specified lifetimes. Typically, the lifetimes of refresh tokens are relatively long. Although refresh tokens aren't revoked when used to acquire new access tokens, you are expected to discard the old refresh token.
POST /{tenant}/oauth2/v2.0/token HTTP/1.1
Host: https://login.microsoftonline.com
Content-Type: application/x-www-form-urlencoded
client_id=6731de76-14a6-49ae-97bc-6eba6914391e
&scope=https://admin.services.crm.dynamics.com/user_impersonation user.read
&refresh_token=OAAABAAAAiL9Kn2Z27UubvWFPbm0gLWQJVzCTE9UkP3pSx1aXxUjq...
&grant_type=refresh_token
&client_secret=JqQX2PNo9bpM0uEihUPzyrh // NOTE: Only required for web apps
And you could refer to this tutorial.

The scenario that you are looking for is called incremental consent. This is totally doable with MSAL. It would be great to know what platform are you developing by the way.
What you can do is to request an access token for user.read and expects MsalUiRequiredException to be thrown. In its catch, you make an interactive call with user.read as scope. With this approach, you will be implementing the incremental consent. Note that user_impersonation will still be available to use after this, and your token cache will now have both scopes.

Related

React & Express JWT Auth: Is it safe enough to store access tokens in Cookies?

I've spent a few days trying to figure out a secure authentication method for SPA/React (client-side).
Most of the tutorials I've read in the wild contradict each other.
One says have to store in Cookies another in Local Storage, one says don't need to use refresh token, one says have to use a refresh token.
I'm building a React SPA app for the frontend and Express for the API (backend). Both are stored in the same domain:
React: example.com
Express: api.example.com or example.com/api
Is it enough to secure my application by using Cookie (access token JWT):
httpOnly:✅
secure: ✅
sameSite: strict
without refresh token
This matches the answer here: https://stackoverflow.com/a/57779076/11340631
The question is:
Is this safe enough?
How long does it take to set the expiration of the access token?
Is this as per Oauth recommendation?: https://datatracker.ietf.org/doc/html/draft-ietf-oauth-browser-based-apps
What if my access token is stolen? For example, my friend is using my PC and he stole my cookies and use it in his PC browser.
I really hope to get the answer here, any answer is appreciated.
It's safe against extracting the token with Cross Site-Scripting, but, without other security controls it might be prone to Cross Site Request Forgery (cookies are automatically attached to a request). Is API accepting key in the cookie or must it be sent in the Authorization Bearer header?
My concern is, that if you're not using refresh token, the access token must have a relative long expiration. OAuth2 was not intended to be used to authentication alone, but together with some session-like solution, for example OpenID Connect and SSO.
The shorter the better, unless it can be revoked any time server-side. If there's no way to revoke the key, the 5 minutes expiration date is, in my opinion maximum. That's why refresh token and session-like endpoint is the must.
OAuth is not designed for web application client's authentication at all. That's the common anti-pattern in many projects I've pentested. https://oauth.net/articles/authentication/
I'm glad for your awareness of such a threat. Access tokens must either live very shortly, or they must be revoked server-side in a some way, for example by utilizing some kind of revoke-list. Or the refresh token with server-side-like session endpoint should be utilized.

Refreshing token with on-behalf-of flow (single-sign-on with Teams)

I have a single-sign-on scenario with Microsoft Teams. See full description in the documentation: https://learn.microsoft.com/en-us/microsoftteams/platform/tabs/how-to/authentication/auth-aad-sso
I am getting an access token by "trading" the "teams" token for an access token.
My question is, how do I refresh this access token? In single-sign-on scenario the "refrehs_token" is not returned (?), so normal OAuth2 refresh flow does not seem to be possible.
Imagine I traded it once, and got the access token that expires in say 2 hours. I use it to access graph API (or whatever), and then the token expires.
What should I do to get a new access token? Can I just ask Teams for a fresh "teams" token and trade it again in case the old one expired? Teams App takes care of refreshing its own tokens, right? When should I do this (when I get "access denied", or just if I see that the token has expired?
Looks like I found the reason - you must pass offline_access as scope request then you get back the refresh_token. That was my issue actually, and it is documented, I just did not read carefully:
https://learn.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-on-behalf-of-flow
refresh_token The refresh token for the requested access token. The calling service can use this token to request another access token after the current access token expires. The refresh token is only provided if the offline_access scope was requested.

How to use refresh token coming from acquiretoken silent in MSAL-browser

I am trying to acquire token by aquiretokensilent after login and then have to do authorization in multiple modules.As documentation of MSAL-browser acquiretokensilent will automatically take care of refresh token.In network tab also i am able to see refresh token.But how to use it, does it automatically replace access token or do i need to do something extra and how i can see that refresh token in the console converting to access token after expiry of access token.I have read lot of documents but not got clearity how to use it.
A refresh token is used for renewing an access token or request access tokens with other scopes.
This official doc indicated that how a refresh token renews/requests a new access token and a new refresh token at the base layer.
And yes, you should call aquiretokensilent before API call, if the access token exists and it is not expired, this function will reply the access token to you from local cache directly, if not, it will request a new access token by refresh token from Azure AD.
For details, see this doc.

Bearer Token authentication and JWT

I've been provided with a REST API which has authentication type bearer (Security Scheme Type: API Key, Header parameter name: Authorization) and which i use to authenticate the user and then fetch other data (i will only create the front end using react).
As a first step the user logs in and i sent his/her username-password to the prementioned REST API and get back an access and a refresh token.
Is anything wrong with storing these 2 tokens in a cookie in order to use them in subsequent requests? How does JWT comes into play regarding these 2 tokens? Is JWT of any use to me in this situation?
There's nothing wrong in storing the tokens in cookies, but if you're planning to have a Single Page Application with React it should be enough to store these tokens in memory. Once the user refreshes the page you can either make them sign in again or perform a silent login in the background to get a new set of tokens. In both cases the session kept on the Authorization Server should kick in and you should get new tokens without the need of user interaction.
Your tokens will be much safer if you don't keep them in cookies.
JWTs are not a requirement for access and refresh tokens. If you don't have to use them I would recommend going with opaque tokens. That said, since you do not have control over the API you might be limited to the format required by the API. If you don't want to be limited by this format you can set up your own gateway which you can use to perform token exchange or introspection and forward requests to the API with proper tokens (something which is called a Phantom Token pattern.
From my understanding of the question, you are using an identity provider which provides you with access token and refresh token for the users. That means it is a authentication as a service REST API at works here.
The REST API requires an authorisation header to be passed along with the username-password to exchange for access token and refresh token for the users. (correct me if I'm wrong) In this case, you might want to keep the authorisation header away from the users (consult the authentication as a service documentation).
You call the REST API with payloads (the user-password) along with headers like this:
Authorization: ACCESS_TOKEN
However the ACCESS_TOKEN is the one provided by the vendor for you to use the REST API. On success call of the REST API, it should return you with a set of access token and refresh token. You can then use this access token and refresh token to safe guard your own API, API that you control to provide service to your users.
The access token and refresh token might just be JWT tokens (again consult the vendor documentation).
Also if you are using an authentication as a service REST API, check the documentation if they provide a client sdk. In that case, it should show you the best practise of handling the access token and refresh token it returned.

OAuth2 grant for interacting between my Angular app and my REST API?

Help me pick the right OAuth2 grant type for my Angular App and my REST API?
UX-wise I want just one login form on my front-end, that would ask for username/pass(no dialog asking for permissions). I think the "Resource Owner(Password) Grant" is the most appropriate for me(since I control front&backend), but I'm not sure how should I handle access token refresh.
Correct me if I wrong about the flow:
When user submits credentials through login form, access token is returned.
I can store this token in LocalStorage to make subsequent Ajax requests with it.
As I understand access tokens should be short-lived. And should be updated with Refresh token. Should the refresh token be returned with the access token after initial login and also stored on the client? If not what is the alternative?
Should there be any session maintained on the server to invoke access token refresh? or I should make calls from front-end to refresh the access token when it is about to expire. But then I need a refresh token on the front-end, right?
As you see there is a mess in my head about refresh token. Would be great to have some clarification or suggestion for another grant implementation.
Backend technology I guess is irrelevant here, but just in case it's Symfony2 with FOSOAuthServerBundle.
When you are calling the TOKEN endpoint (for every grant_type possible) on a OAuth Server, you get an access_token but other information as well (I think there are all here):
{
access_token: // your short-lived token
expires_in: // number of seconds before the access_token is invalid
token_type: // the type of the access_token
scope: // scopes of the access_token
refresh_token: // long-lived token to get a new access_token
}
You need, in my opinion, all these information (maybe the scope is unused, but all others will be used later). You have to store the access_token to ba able to make API calls. After seconds, your access_token will not work anymore. You will need to get a new one. You can either ask the user to log in AGAIN or use the refresh_token.
You will have to call the OAuth Server on the TOKEN endpoint but with a grant_type: refresh_token. You will have to provide the refresh_token from the first request (among other information) and in return you will have the same response as above. In fact, I think you will have to do that every time an access_token is expired. In my opinion, the server side does not know anything about sessions or connected users. It knows about valid and invalid access_token.
This is OAuth. If you don't want to have to refresh everytime, you can make a long-lived access_token (by setting the expires_in), I think this is the only solution that makes sens in an OAuth context.
Do you need some clarification about OAuth in general?

Resources