Azure AD OAuth2.0: I dont get a refresh token - azure

when a client application (such as a webpage using our api) is connecting to a Azure AD OAuth2.0-protected web api
To get the access token, the client applications make a POST to this
https://login.microsoftonline.com/{tenant}/oauth2/token
But the client applcation does not get a refresh token.Is that not needed in the "client application" scenario?
This is what they get
"token_type": "Bearer",
"expires_in": "3600",
"ext_expires_in": "0",
"expires_on": "1531906803",
"not_before": "1531902903",
"resource": "https://our-api.azurewebsites.net",
"access_token": "YtNGEzZi1hZGYyLTExNjU4N......rdFqQ"
The token works fine and it SEEMS that it never expires.

If you got the token with client credentials (client id + client secret or certificate), then you don't get a refresh token.
In this scenario, you can always get a new access token with the application's credentials alone, so you do not need refresh tokens.
In the case of flows which have user context, you get a refresh token since you cannot repeat the user login at will, and must use the refresh token to get a fresh token.

You need add a special scope offline_access when you request authorization_code to receive refresh_token as the result. Check it out, may be it is you case :)

Related

ADB2C refresh_token always expires in one day

I've been struggling with adb2c for a while now. In particular the refresh flow. I'm using the latest version of msal-browser and everthing works fine, refreshing the token works well. The only problem is that the token endpoint returns a refresh_token that will always expire in one day. In this case, a user can only be logged in for a day, after that, the user will always have to re-authorize. Here is an example of the endpoint and what it returns directly after logging in. (note that I have set the access_token expire time on 5 mins for testing purposes)
Endpoint:
https://{b2c_domain.onmicrosoft.com/{b2c_policy}/oauth2/v2.0/token
Response:
{
"access_token": "{access_token_hidden}",
"id_token": "{id_token_hidden}",
"token_type": "Bearer",
"not_before": 1610023338,
"expires_in": 300,
"expires_on": 1610023638,
"resource": "{resource_hidden}",
"client_info": "{client_info}",
"scope": "https://{adb2c_domain_hidden}.onmicrosoft.com/api/user_impersonation",
"refresh_token": "{refresh_token_hidden}",
"refresh_token_expires_in": 86400
}
When, at some point, the application will try to refresh a token, it will call the token endpoint again. This is what a second response looks like:
{
"access_token": "{access_token_hidden}",
"id_token": "{id_token_hidden}",
"token_type": "Bearer",
"not_before": 1610023891,
"expires_in": 300,
"expires_on": 1610024191,
"resource": "{resource_hidden}",
"client_info": "{client_info}",
"scope": "https://{adb2c_domain_hidden}.onmicrosoft.com/api/user_impersonation",
"refresh_token": "{refresh_token_hidden}",
"refresh_token_expires_in": 85846
}
The refresh_token_expires_in is not rolling. But that is understandable, the user should not always stay logged in. But, in my adb2c policy the following settings are active:
I would assume, as I have configured in the settings, the refresh token should at least be active for 14 days. If not, even up to 90 days? I can play with the settings, but it will always give me a refresh_token that lasts for 1 day. Does anyone has any experience with this or has a possible solution? Thanks!
If you are using the Msal-Browser which implements the code grant with PKCE in SPA application. For this case, you will get the refresh token which will have a expiry of 24 hours and that is not rolling. After 24 hours you need to go to /authorization endpoint of azure ad to get the new access and refresh token. This can also be also non-interactive flow if the browser has the valid login session.
In the Msal-browser library, If you have configured the session more than 24 hours then you can perform the Silent login with ssoSilent(), it require you to send the login_hint.
Yes, as you think, the lifetime of the refresh token can be up to 90 days. If you need to configure the lifetime of the refresh token, you should use powershell to create a token lifetime policy, and then assign the policy to your service principal to set the token lifetime. See: here.
Update:
I just used the Azure AD B2C portal to set the lifetime of the refresh token to 14 days, and then tested it with the ROPC user flow, and the result was that it did take effect. The refresh token I got was 14 days.
So, please make sure that the user flow that you set the lifetime of for the refresh token is the user flow you are using, which is very important!
By the way, your endpoint is wrong, it should be:
https://<tenant-name>.b2clogin.com/<tenant-name>.onmicrosoft.com/{b2c_policy}/oauth2/v2.0/token
2.
3.

Not getting refresh token and id_token with Azure AD OAuth2.0 ROPC flow using username and password

I am using ROPC Flow with user details and client details to get Access token and refresh token. But I am only getting Access Token and this expires in 1 hour.
My frontend app has sign-in window where we provide AD user creds, this makes a post request and got FE with successful auth.
I have 2 questions:
Getting CORS issue while making user sign-in request using http://localhost:3000 with access-control-allow-origin header error.
I would like to get refresh token for Continues App login OR do I set the lifetime of the access token to a day.
REQUEST:
// Line breaks and spaces are for legibility only. This is a public client, so no secret is required.
POST {tenant}/oauth2/v2.0/token
Host: login.microsoftonline.com
Content-Type: application/x-www-form-urlencoded
client_id=6731de76-14a6-49ae-97bc-6eba6914391e
&scope=user.read%20openid%20profile%20offline_access
&username=MyUsername#myTenant.com
&password=SuperS3cret
&grant_type=password
RESPONSE:
{
"token_type": "Bearer",
"scope": "api://94849942785375897059789375379/FIles.Read",
"expires_in": 3598,
"ext_expires_in": 3598,
"access_token": 8YU4bMhafsfhaeoahehviyy8786w89ufo2ofj29h8gMWnB633NLWn7JQ"
}
You need to add offline_access and openid to the scope parameter when requesting the token, try to add them, you will get the id token and refresh token.
Update:
Your application will need a back-end that will fetch the data and return it to the front-end. So try to call the token endpoint from the back-end .

I can't get email or profile scopes for an Azure B2C application, nor can I call the OIDC UserInfo endpoint

I'm finding Azure B2C really confusing. Currently I am using oauth2_proxy behind an nginx ingress controller in a test (single node) AKS kubernetes environment. I have made a slight change to oauth2_proxy to redirect upon error to chain Workflows together (like password recovery link etc.) and everything is working so far. I get an authorisation cookie from oath2_proxy and the ingress controller lets me through.
My next step is to work out what the username is, and maybe gather some more informaton. I think I can get some of the information in the id_token, but I am failing to see "email" and "preferred_username". Apparently these are only available if my token has the "email" and "profile" scopes, but I cannot work out how to get those scopes on my B2C App.
Currently I have a test application. In it's API permissions area I have a single "read" permission so that I have a resource to request to get an access_token. I also have "email", "offline_access", "openid", "profile" and "User.Read" permissions from "Microsoft Graph" - all permissions are granted by the admin on the API permissions screen.
The process I have been following up to now for testing is to run a signin workflow, selecting my API in the resources dropdown. I then copy the "Code" into a token request in postman, and then try both the "https://graph.microsoft.com/v1.0/me" and the "https://graph.microsoft.com/oidc/userinfo" endpoints with both the "id_token" and the "access_token". Both of these respond with "InvalidAuthenticationToken", message "Access token validation failure".
I had since noticed that my resources dropdown still only contains "read" and "openid" access rights, so I have been copying the "run userflow" url and inserting the scopes for "email", "offline_access", "openid" and "profile". I have also ensured that my call to the "token" endpoint contains these scopes. The response from the token endpoint only returns scopes "read offline_access openid", so "profile" and "email" are missing.
I don't know how to configure my app registration in B2C so that the "email" and "profile" scopes become available. Since "openid" appears in the resource drop down, I would expect "email" and "profile to turn up in there, but they don't. My token calls definitely show that the scopes that I need are not returned.
My workflow url looks as follows:
https://********.b2clogin.com/********.onmicrosoft.com/oauth2/v2.0/authorize?p=B2C_1_signup_signin&client_id=********&nonce=defaultNonce&redirect_uri=https%3A%2F%2Fjwt.ms&scope=openid%20user.read%20email%20profile%20offline_access%20https%3A%2F%2F********.onmicrosoft.com%2Ftestapp%2Fread&response_type=code&prompt=login
My token call looks as follows (using the code value from the workflow):
https://********.b2clogin.com/********/b2c_1_signup_signin/oauth2/v2.0/token?grant_type=authorization_code&client_id=********&response_type=code&redirect_uri=https://jwt.ms&response_mode=query&scope=https://********.onmicrosoft.com/apptest/read openid offline_access email profile&code=******CODE FROM WORKFLOW CALLBACK******
Token response is like:
{
"access_token": "******BIG LONG BASE64******",
"id_token": "******BIG LONG BASE64******",
"token_type": "Bearer",
"not_before": 1591607270,
"expires_in": 3600,
"expires_on": 1591610870,
"resource": "********",
"id_token_expires_in": 3600,
"profile_info": "******BASE64******",
"scope": "https://********.onmicrosoft.com/testapp/read offline_access openid",
"refresh_token": "******BASE64******",
"refresh_token_expires_in": 1209600
}
OIDC endpoint call like this:
https://graph.microsoft.com/oidc/userinfo
HAS HEADERS
Content-Type: application/json
Authorization: Bearer ********BASE64 from access_token********
Any help would be appreciated. i.e. how do I return additional scopes + how do I call the OIDC UserInfo endpoint.
Thanks.
I struggled with a similar issue a while back, where I wanted my API to use the access token to look up user info. Azure AD does not work in a standards compliant way:
Calling User Info requires a separate graph token
You have to use a token exchange request to get the graph token
Here are some resources of mine which I think are related and will hopefully give you enough info to resolve your problem. I think right now you are getting the error from Step 14 of the blog post.
Token Exchange + User Info Lookup C# Code
Blog Post on Azure AD Settings related to Graph / User Info

Azure access token generation from Postman

I wanted to generate Azure token from Postman for API authorization in my project. I am able to generate token using below API request but getting the below error message "Authorization denied for this request" while using the generated token in another API request.
Endpoint#
https://login.microsoftonline.com/:tenant_id/oauth2/token
Params#
tenant_id:As per id generation by azure.
Body# (Form-data)
grant_type:client_credentials
client_id:As per id generation by azure.
client_secret:As per id generation by azure.
resource:Required URL
Response#
"token_type": "Bearer",
"expires_in": "foo",
"ext_expires_in": "foo",
"expires_on": "foo",
"not_before": "foo",
"resource": "foo",
"access_token":foo
Since the above returned token is not accepted, I had passed username and password as well in body of the request but ended up with same results. Also azure did not consider my credentials even they are wrong.
Could you please assist what else I need to send in the response to get valid token id?
The Valid format for client_credentials authentication flow is like below:
Azure Portal Credentials For App Id and Tenant Id:
Application Secret from Portal:
Token Endpoint Or URL:
https://login.microsoftonline.com/YourTenantName.onmicrosoft.com/oauth2/token
Request Param:
grant_type:client_credentials
client_id:b603c7be_Your_App_ID_e6921e61f925
client_secret:Vxf1Sl_Your_App_Secret_2XDSeZ8wL/Yp8ns4sc=
resource:https://graph.microsoft.com
PostMan Sample:
Token On Response:
Expose Your Own API:
When You want to authorize your own API you have add it here. So that your token will contain this permission and this API can be accessed. Refer this docs
For more clarity you could refer official docs
You should try adding "X-ZUMO-AUTH" header to your request when using the generated token.
GET https://<appname>.azurewebsites.net/api/products/1
X-ZUMO-AUTH: <authenticationToken_value>
https://learn.microsoft.com/en-us/azure/app-service/app-service-authentication-how-to

Security - JWT and Oauth2 (refresh token)

I have a angular client app and a .net web api server.
I'm trying to understand how to implement security in the best way using tokens.
I thought about few options, and I don't know which one is the best, or if there is a better way.
JWT with expiration
1.User login with credentials -> Server returns a JWT with expiration (for example 60 minutes from login time). Each valid request to the server within this 60 minutes the server returns a new JWT token with a new expiration of 60 minutes. If user didn't send server request for 60 minutes he must login again.
This solution is very similiar to sessions.
Oauth2 - I don't think I understand this protocol correctly, so I apologize if what I'm saying is not correct.
2.User login with credentials -> user gets a refresh_token and access_token.
For every request, the client attaches the access_token. If server returns 401 (unauthorized) the client uses the refresh_token to create a new access_token and re-send the failed request with the new token.
The problem in this flow, for me, is that I don't know if I got unauthorized because the token was invalid or the user tried to access unauthorized resources.
This led me to a third solution.
3.User login with credentials -> user gets a refresh_token, access_token and access_token_expiration. When the user wants to create a request to the server, he checks if access_token has expired. If expired, the client will request a new access_token with new expiration and only then perfroms the request.
And 2 more little question about auth2:
1.Why do I have a refresh_token and access_token? Both of them are stored in client local storage. Why not to always use the refresh_token? For the server it makes sense to have a refresh_token and access_token since the refresh_token is secured.
2.Does the refresh token have an expiration date?
If it does, how can I create a new refresh token?
If it doesn't, isn't it a little unsave to give the ability to stay connected forever?
Thank you very much for your help
Option 3, login with credentials and getting an access token, refresh token and expiration time is the usual way.
eg.:
{
"access_token": "eyJ0eXA....CqVJcc",
"token_type": "bearer",
"expires_in": 3599,
"refresh_token": "AQAAAN...H2JXjIUAQ"
}
the expiration time of the JWT access token can also be found in the token itself in the payload field exp, in form of a UNIX timestamp:
{
...
"exp": 1500547257,
"nbf": 1500543657
...
}
With that information you can implement your own mechanism to check if your access token is still valid and refresh it when necessary.
The refresh token usually also expires. When the refresh token is expired, you need to start again with the credentials.
Additionally you can read this for further information about the topic: https://auth0.com/learn/refresh-tokens/
And here is a tutorial that talks about handling of refresh tokens in Angular:
http://bitoftech.net/2014/07/16/enable-oauth-refresh-tokens-angularjs-app-using-asp-net-web-api-2-owin/

Resources