I'm writing a program that automates some actions with my QuickBooks account (using Node js).But expires refresh token also, what can i did?I have this error message.
Error: The provided authorization grant (e.g., authorization code, resource owner credentials) or refresh token is invalid, expired, revoked, does not match the redirection URI used in the authorization request, or was issued to another client.
You can refer the official node-oauth2.0 lib.
https://www.npmjs.com/package/intuit-oauth#refresh-access_token
You need to generate new accessToken using the latest refreshToken.
Ref docs - https://developer.intuit.com/app/developer/qbo/docs/develop/authentication-and-authorization/oauth-2.0
Related
When a user logs out of Azure B2C using the MSAL library on a mobile device this only clears the local cache. The remote session on the server still exists which means any existing refresh tokens could still be used.
From searching I know that the Microsoft Graph API can be used to revoke the current user's sign in session, and therefore invalidate all current refresh tokens. I believe I am doing this, but the refresh tokens keep remaining active.
Here is my flow:
I get a token for user A (I tried this with auth code flow and ROPC but I don't believe that should make a differnce).
I confirmed that I can get a new access token by using the current refresh token that is returned in a Postman call -
{{b2c_login_url}}/B2C_1_ROPC_SignIn/oauth2/v2.0/token?grant_type=refresh_token&client_id={{b2c_ropc_client_id}}&refresh_token=xxxxx&scope={{b2c_scopes}}&redirect_uri={{b2c_api_redirect_uri}}
This returns a new access token as expected.
I then take the azure userId value ("oid" property in the access token) and pass that through to my API that then runs the following code.
var graphClient = GetGraphClient();
var result = await graphClient.Users["{" + userId + "}"]
.RevokeSignInSessions()
.Request()
.PostAsync();
return result.GetValueOrDefault();
I can see that the result of this expression is true. I can also go onto the Azure B2C user details and see that "StsRefreshTokensValidFrom" has been updated to the current date time as expected.
Now, I run the exact same http request I ran previously using the refresh token to get another access token, but this time, it should fail. However, I continue to get new access tokens.
The strange thing is that I am sure I tested this previously, tried to get a new token, and it failed as I'd expect. But now it will always return me new tokens.
I feel I am missing something here. Any advice?
I tried to reproduce the same in my environment and got below results:
I generated token for a B2C user using ROPC flow via Postman with parameters as below:
POST https://<tenant_name>.b2clogin.com/<tenant_name>.onmicrosoft.com/<policy>/oauth2/v2.0/token
client_id : xxxxx-xxxx-xxxx-xxxxxxxx
grant_type : password
scope : https://<tenant_name>.onmicrosoft.com/web_api/api.read offline_access
username : b2c_username
password : password
Response:
Using the above refresh token, I'm able to generate access token successfully like below:
POST https://<tenant_name>.b2clogin.com/<tenant_name>.onmicrosoft.com/<policy>/oauth2/v2.0/token
client_id : xxxxx-xxxx-xxxx-xxxxxxxx
grant_type:refresh_token
scope:https://<tenant_name>.onmicrosoft.com/web_api/api.read
redirect_uri:https://jwt.ms
refresh_token:paste_refresh_token
Response:
To revoke refresh tokens, I ran below query via Graph Explorer like this:
POST https://graph.microsoft.com/beta/users/<user_id>/invalidateAllRefreshTokens
Response:
Code Sample in C#:
GraphServiceClient graphClient = new GraphServiceClient( authProvider );
await graphClient.Users["userid"]
.InvalidateAllRefreshTokens()
.Request()
.PostAsync();
To confirm that, I checked user's details in Portal like below:
When I tried to get access token with same refresh token, I got error saying token is revoked like below:
After revoking the tokens from Graph API, it may take up to 5 minutes to work.
If you run the query for access token as soon as you revoked the refresh tokens, you may still get access token.
So, wait for 5-10 minutes and try to get the access token with same query. Then, you won't be getting access token as the refresh token will be revoked at that time.
From last couple of weeks we have few clients complaining that our app is auto revoking Office365 oauth every 1 hour. This is the typical behiviour as access token have validity of 1 hour, so our app is designed to auto refresh the access token using refresh token captured during oauth.
This seems to be not working for atleast few customers from last few weeks. Below exception is thrown back by Office365 token api - https://login.windows.net/common/oauth2/token
{"error":"invalid_grant","error_description":"AADSTS9002313: Invalid request. Request is malformed or invalid.\r\nTrace ID: 7f80c2c3-41bc-41bd-8304-b56969c83a00\r\nCorrelation ID: 5a08714a-1e7d-4f32-814d-146bc721e8ab\r\nTimestamp: 2020-10-12 05:42:11Z","error_codes":[9002313],"timestamp":"2020-10-12 05:42:11Z","trace_id":"7f80c2c3-41bc-41bd-8304-b56969c83a00","correlation_id":"5a08714a-1e7d-4f32-814d-146bc721e8ab","error_uri":"https://login.windows.net/error?code=9002313"}
Here, the error code '9002313' states there is some issue related to auth parameters especially 'client_id' of our azure app. (reference)
Below data is sent to fetch new access token
client_id (related to azure app)
client_secret (related to azure app)
grant_type = 'refresh_token'
refresh_token
Edit 1: Update token endpoint to v2.0
Request URI
POST https://login.microsoftonline.com/common/oauth2/v2.0/token
Request Body
client_id=<client-id> &scope=https://outlook.office365.com/Calendars.ReadWrite https://outlook.office365.com/Contacts.ReadWrite https://outlook.office365.com/Mail.ReadWrite &refresh_token=OAAABAAAAiL9Kn2Z27UubvWFPbm0gLWQJVzCTE9UkP3pSx1aXxUjq... &grant_type=refresh_token &client_secret=<client-secret>
Reponse Body
{"error":"invalid_grant","error_description":"AADSTS9002313: Invalid request. Request is malformed or invalid.\r\nTrace ID: 4447c69e-09d6-4a00-8dfe-735106d71200\r\nCorrelation ID: 1820e135-a511-4516-99d9-b6cebb342eb2\r\nTimestamp: 2020-10-13 03:39:37Z","error_codes":[9002313],"timestamp":"2020-10-13 03:39:37Z","trace_id":"4447c69e-09d6-4a00-8dfe-735106d71200","correlation_id":"1820e135-a511-4516-99d9-b6cebb342eb2","error_uri":"https://login.microsoftonline.com/error?code=9002313"}
Your authority is old and you missed the scope in the request body(if use the v2.0 endpoint), if you want to get a new access token for O365 with the refresh token, use the sample request below.
Request url:
POST https://login.microsoftonline.com/common/oauth2/v2.0/token
Request body:
client_id=<client-id>
&scope=https://outlook.office365.com/.default
&refresh_token=OAAABAAAAiL9Kn2Z27UubvWFPbm0gLWQJVzCTE9UkP3pSx1aXxUjq...
&grant_type=refresh_token
&client_secret=<client-secret>
For more details, refer to the doc - Refresh the access token.
Update:
I test it for you, it works on my side. Make sure you also get the refresh token with the v2.0 endpoint, see here.
The permissions for my app:
Test to get a new access token in the postman after getting the refresh token.
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 using the Easy Auth feature of Azure App Service and I am trying to refresh a token with the Google provider.
I followed the Chris Gillum article and correctly called .auth/login/google with the access_type=offline parameter. Then I called .auth/refreshwhich return me a 200 OK with a new authenticationToken. However, when I check the claims of this ZUMO token by calling .auth/me, I can see that the Google token is in fact not refreshed despite the previous successful response. The exp claims (corresponding to Expiration Time) is the same as the previous token.
I tried several scenario : refresh the token immediately after receiving it, 10 minutes before the expiration time and after the expiration time (when the token is no longer valid) but in every scenario, Easy Auth return me a new ZUMO token but the Google token associated is always the same.
Is it normal for the .auth/refresh endpoint to always return the same token (same exp claims) with the Google provider ?
As Exchange authorization code for refresh and access tokens states about the refresh_token:
A token that you can use to obtain a new access token. Refresh tokens are valid until the user revokes access. Note that refresh tokens are always returned for installed applications.
And the response from Refreshing an access token only contains the access_token,expires_in (The remaining lifetime of the access token in seconds),token_type.
Is it normal for the .auth/refresh endpoint to always return the same token (same exp claims) with the Google provider ?
Using the Log stream under the MONITORING section of your app service, you could find the detailed log when calling .auth/refresh as follows:
Moreover, the exp claim when calling .auth/me represents the expire time for the authenticationToken instead of the refresh_token.
And you could leverage jwt.io to decode your authenticationToken and compare it with the exp user claim.
This is the policy update i made.
Set-AzureADPolicy -Id 971c05df-810a-430d-b509-571d61712783 -DisplayName "OrganizationDefaultPolicyScenario" -Definition #('{"TokenLifetimePolicy":{"Version":1,"MaxInactiveTime":"14.00:00:00","MaxAgeSingleFactor":"90.00:00:00","MaxAgeMultiFactor":"90.00:00:00"}}')
After updating this policy, i tried to generate refresh token using method AcquireTokenByRefreshToken(RefreshToken, clientId).
Parameters provided for above refresh token generation method:
RefreshToken – Refresh token i got from the method AcquireToken
Client id - Client id of corresponding Azure AD
But still i can get refresh token with expiry as 1 hour. Did i miss anything?
Please help me to resolve this problem.
Thanks in advance.
As I known, ADAL caches refresh token and will automagically use it whenever you call AcquireToken and the requested token need renewing(even you want to get new access token for different resource).
The refresh token in the AuthenticationResults , and corresponding AcquireTokenByRefreshToken method, is one such violation.
You can see more details about this issue in this article.
See more details about refresh token in ADAL in this link .