MSAL + OAUTH token refresh - azure

I may be answering my own question here but would like some assurance.
For a Azure event hub producer client (.net) using OAUTH token authN will token refresh be performed within the MSAL Classes OR would it be connection/message?
Thanks

MSAL handles token refresh.
When you ask for a token silently, MSAL will first check if it has a token in cache that is still valid.
If yes, it'll return that.
If not, it checks if there is a refresh token in cache.
It'll then try to use that to get new tokens, cache them, and return them.
If the refresh fails, you will get an exception.

Related

Using a refresh token to get a bot access token replaces the refresh token

I am trying to convert my Slack app code to use bot refresh tokens rather than the old bot token when accessing the web client api.
I have been able to call the https://slack.com/api/oauth.v2.access endpoint both from Postman and using the Slack Webclient node.js module.
I am passing in my app's client id, client secret, my bot refresh token and a grant_type of refresh_token.
In both cases the Slack API responds with a new access_token but sometimes I also get a new refresh_token and I can't use my original refresh token to get more access tokens.
This doesn't seem correct;
I have stored the refresh token from the app OAuth web page in a secret store. Typically you would use the non-expiring refresh token to get access tokens as required.
Since Slack is also refreshing the refresh_token each time, I am unable to rely on the secret store and I will need to persist this refresh token in some other place, which is potentially insecure.
When the refresh token changes it also invalidates the installation object that I have persisted and I need to re-do the "Add to Slack" process to fix that.
Am I doing something wrong, such as using the wrong endpoint, or is the Slack API "broken"?
Update & clarification
Thanks for those in the comments who have pointed out that issuing a new refresh token is in the OAuth spec.
The reason that this is a problem for me is that I need bot access tokens in two places. In one of those places the token refresh is handled by Slack's Bolt framework. In the other I am handling token refresh myself.
Since a new refresh token is issued when the access token is refreshed, one of those two places no longer knows the "current" refresh token, so it fails next time it tries to refresh its access token. Which one fails depends on which one refreshed the token.
The comment on the refresh token in the Slack OAuth page for the app says "never expires", but this is misleading as while it doesn't expire per-se, the value shown in the page does become invalid when a new access token is generated from it.
This is quite different behaviour from other "never expires" tokens such as the app client secret, which is only invalidated if you manually re-issue it in the settings page.
Prior to token rotation, slack apps used a non-expiring "Bot token" that could be used in multiple places. It seems that you cannot get the exact behaviour with OAuth and token rotation.
As #Codebling and #morganney pointed out, it is within the OAuth spec for a new refresh token to be issued alongside a new access token.
My problem arises because I need an access token in two separate parts of my app. One part is using Slack's Bolt framework and the other isn't. This leads to a potential for conflict where the refresh token is updated by one or the other parts of my app.
The solution is to leverage the Slack Bolt InstallProvider in the non-Bolt code in my app (This requires that the non-Bolt code can access the same InstallationStore implementation as the Bolt code).
Using the InstallProvider ensures that if a token refresh is required, the InstallationStore is always updated and a consistent set of tokens (refresh and access) is available to both parts of my app.
In the non-Bolt code I use the following to obtain an access token to call the Slack Web client:
const installer = new InstallProvider({
clientId: process.env.SLACK_CLIENT_ID!,
clientSecret: process.env.SLACK_CLIENT_SECRET!,
installationStore: new MyInstallationStore(),
stateSecret: 'someSecret'
})
const authorizeResult = await installer.authorize({
isEnterpriseInstall: enterpriseId !== undefined,
enterpriseId: enterpriseId,
teamId: teamId
})
if (authorizeResult.botToken) {
await this.webclient.chat.postMessage({
channel: slackId,
blocks: blocks,
icon_emoji: `:wave:`,
text: "Welcome message",
token: authorizeResult.botToken,
});
}
You are doing nothing wrong. It is, however, on-spec to re-issue refresh tokens.
The relevant section of the spec is Section 1.5. Refresh Token. Step H says (emphasis mine):
(H) The authorization server authenticates the client and validates
the refresh token, and if valid, issues a new access token (and,
optionally, a new refresh token).
You'll unfortunately have to accommodate this behavior in your code. It's not clear why you cannot change values in your secret store (or why values that get updated cannot be stored in your secret store). Feel free to post some code if you'd like some suggestions

Do I use a refresh token?

I have an application that doesn't have user accounts so doesn't need a login. I'm currently authenticating using JWT via a /get-token endpoint in my api that's called as soon as the UI starts and returns a bearer token that's used for the calls for the calls moving forwards/
When that token expires, i'm a little confused at how to handle that. I was thinking using a refresh token but all the tutorials i've seen are passing the refresh token back to the UI, isn't that unsafe? I was always under the idea that the refresh token was internal and is only used on the server to refresh expired tokens.
What's the best way to handle this?
Refresh tokens carry the information necessary to get a new access token. In other words, whenever an access token is required to access a specific resource, a client may use a refresh token to get a new access token issued by the authentication server. Common use cases include getting new access tokens after old ones have expired, or getting access to a new resource for the first time. Refresh tokens can also expire but are rather long-lived. Refresh tokens are usually subject to strict storage requirements to ensure they are not leaked. They can also be blacklisted by the authorization server.

Azure v2.0 Refresh Token, returns another Refresh Token

Azure AD is granting my application access tokens and a refresh token. When I use the refresh token to get a new access token, in return I get a new access token and a NEW refresh token.
Azure AD does not specify like Google Suite how many refresh tokens are allowed. But to the root of the problem, I don't want a refresh token being recreated and sent back, every time I use a refresh token. What is happening here? How do I stop this?
Returning of new refresh token is part of the OpenID Connect Protocol Specification which references the OAuth Authorization Framework section 5.1 for clarity.
Indeed the return of a refresh token is optional, but the implementation in Azure AD is so that it always returns a refresh token. I personally see no issue with it. Just throw away the last saved refresh token and keep the new one you got.
You cannot control this, it is done by design. It is also in complience with the OAuth 2.0 spec:
The authorization server authenticates the client and validates the refresh token, and if valid, issues a new access token (and,optionally, a new refresh token).
As for "floating out there", this only happens if you make it happen. If your app "forgets" the old refresh token then it is gone.

Securing Oauth2 refresh_token

I'm using Oauth2 to handle authentication in my system. While the authentication works, I'm worried about the security of my refresh token endpoint. The front-end calls this endpoint to get a new access token after it expires.
My question is how would you prevent someone from calling that endpoint and getting a new access token? Would you use the access token to authenticate yourself? At the moment I'm using these tokens to authenticate API calls on a separate service.
The endpoint currently supports csrf, but that's probably not enough.
Thank you!
The refresh token is used to get the new access token. That is where the authentication happens.
You can decrease the time that a refresh token is valid.
You can also choose if you want the refresh token to be renewed or not with each call to refresh the access token.
Unauthenticated clients cannot call the refresh token endpoint and get a new access token.

How to get a new Google oauth access token from refresh token in passportjs

there seems to be some conflicting advice on how to get an access token from a refresh token:
This SO answer says passportjs doesn't get involved with refreshing the access token and it should be done via cron job:
Refresh token in Passport.js
This SO answer says "No need for any cron jobs...when the user requests data from the API using an access token that has expired, this should trigger your framework to fail, renew, then retry."
OAuth 2.0 - When should an access token be renewed with refresh token?
What's the simplest way to ensure we're always giving Google a valid access token? Right now, we're just storing the refresh token in the database and never using it, which forces users through the "allow / deny permissions" flow every time their access token expires.
There are a few approaches. One is to just detect when the access token fails (with 401 I believe) and then refresh it and re-use it. However, most of the APIs that yield access tokens also tell you their expiry time, so you can just remember that and, when you’re about to use, if it’s less than say 10 min before expiry time, refresh then. If all else fails you could use the tokeninfo endpoint when you get a new access token, to find out its lifetime.

Resources