To my understanding, it can create a short live access token. But does it have a single use access token that is similar to what the Authorization code is?
What is the best approach in doing it? I have thought about using refresh token, but that is still short live, not single(one-time use).
OR can it do it this way:
App1 needs to get an access token from IS4 to call App2, but that token can be used once only. Can the IS4 keep something in the state and App2 needs to call the introspection endpoint of IS4 (rather than local validation of the JWT) and the IS4 checks its state and allow it once?
Thanks in advance.
You can configure IdentityServer to put a unique value (the jti claim) into an access token. That's a client setting.
This can be used to maintain a replay cache at the API to reject token that are used more than once. The token lifetime helps to trim the cache.
Related
I m using a client credential flow to access the API. I am getting the access token each time client make a call to Web API which seem to me may not be good but not sure why. I looked through web I am getting mix answer, some say Client Credential flow doesn't return refresh token some say possible but it is not clear how. I looked at the project where it seem to store the token in the cache but doesn't show how it can be use when needing to get the access token.
Even if Client Credential flow doesn't support or send refresh token. I am searching for a way to store the access token and use it until is is not expired and get a new one when it is expire. This is where I am looking for support.
Beside that I do have relevant question.
Should I just get the access token each time? what is the downfall of it?
Should I include a Test method is Web Api to validate if the token is expired and return "Unauthorize" response based on that response I get the new token? With this approach, I will calling the API each time I need to access the API for actual purpose. So wouldn't I just get the access token from the Authorization server (Microsoft Identity platform).
Have a look at these resources:
https://github.com/AzureAD/microsoft-authentication-library-for-dotnet/wiki/Client-credential-flows
https://learn.microsoft.com/en-us/azure/active-directory/develop/msal-net-token-cache-serialization?tabs=aspnet
One possible solution is to implement internally your own solution:
Get the Token.
A Dictionary is going to hold the (API type) as a key and the corresponding token as its value.
Next call check if the token exists in your Dic(TryGetValu(ket, out param)).
Check "ExpiresOn" on the AuthenticationResult (the Token) and compare its time for validation.
Remember to maintain your Dic by Updating or adding new tokens.
Watching this video, it details in OAuth2 that the client application first has to get the authorization grant from the Authorization server and then use that grant to get a token before being able to access the resource server. What purpose does the grant serve? Why not give the client the token right away after the user signs on with his/her username and password?
Because it is more secure, for some application types.
What you describe is so called authorization-code-flow. It is normally used for "classical" web applications, where only the backend needs to access resource server. The exchange of authorization code to access token happens on the backend and access token never leaves it. Exchange can be done only once and in addition client id and secret (stored on the backend) are necessary.
Single-Page-Applications often use implicit-flow where access token is delivered to the frontend directly in the URL.
See more here:
IdentityServer Flows
EDIT: Q: "I still don't see how it is more secure given that you have to have the grant in order to get the token. Why need 2 things instead of just 1 thing to access the resource? If someone steals the token, they can access the resource anyway – stackjlei"
"Stealing" access token will work independent on how your application acquires it. However, stealing access token on the backend is much more difficult than on the frontend.
Authorization code is delivered to the backend also over the frontend but the risk that someone intercepts and uses it is tiny:
It can be exchanged only once.
You need client-id and client-secret in order to exchange it. Client-secret is only available on the backend.
Normally, authorization code will be exchanged by your backend to access-token immediately. So the lifetime of it is just several seconds. It does not matter if someone gets hold of used authorization code afterwards.
In your scenario there could be two servers, an Authorization and a Resource one.
It could be only one as well, but let's imagine this scenario.
The purpose of the Authorization Server is to issue short lived access tokens to known clients. The clients identify themselves via their CLientID and CLientSecret.
The Authorization Server ( AS ) holds the list of clients and their secrets and first checks to make sure the passed values match its list. If they do, it issues a short lived token.
Then the client can talk to the Resource Server ( RS ), while the token is valid. Once the token expires, a new one can be requested or the expired one can be refreshed if that is allowed by the Authorization Server.
The whole point here is security, Normally, the access tokens are passed in the Authorization header of the request and that request needs to be over https to make sure that the data can't be stolen. If, somehow, someone gets hold of an access token, they can only use it until it expires, hence why the short life of the tokens is actually very important. That's why you don't issue one token which never expires.
You have different type of OAuth. On type doesn't require to use the 'grant' authorization. It depend who are the user/application, the ressource owner and the server API.
This way, you - as a user - don't send the password to the application. The application will only use the grant token to gain access to your ressources.
I think this tuto is a pretty good thing if you want more details
https://www.digitalocean.com/community/tutorials/an-introduction-to-oauth-2
Per Google's docs it would seem refresh tokens are only necessary for offline applications (applications that may run into an expired access token when the user isn't around).
Access tokens periodically expire. You can refresh an access token
without prompting the user for permission (including when the user is
not present) if you requested offline access to the scopes associated
with the token.
...
Requesting offline access is a requirement for any application that
needs to access a Google API when the user is not present. For
example, an app that performs backup services or executes actions at
predetermined times needs to be able to refresh its access token when
the user is not present. The default style of access is called online.
However, a description of refresh tokens in general and this question in particular both seem to imply that refresh tokens are needed anytime you want to request a new access token.
I think I would agree with Google's explanation and not use refresh tokens. My experience with OIDC providers has been that refresh works as follows:
User requests protected resource from client server
Client server determines access token has expired.
Client server redirects user to OP auth endpoint
OP authenticates user without interaction due to cookies stored on user's browser with OP's domain.
Client server finishes the request.
The user might see a few redirects but other than that the re-authentication went by without any interaction from them. Given this, is it necessary to bother with refresh tokens if the user will always be present at the application?
My biggest concern with using refresh tokens for online apps is that it takes away transparency from the user.
Refresh tokens facilitate long term access and should be stored safely. But they also don't provide a natural way to "sign out", and (most importantly) it becomes completely opaque how, when and from where your data is accessed, as the often used scope name offline_access suggests.
OIDC offers a front channel mechanism prompt=none that largely leads to the same effect (i.e. new tokens), and without needing intermediate redirects if the re-authentication is performed inside an iframe.
Hence in my opinion you and Google are right and the answer must be: No, don't use refresh tokens if the user is present.
No, it is not necessary to bother with refresh tokens if the user will always be present at the application. The reasoning is largely the OP describes.
But there are reasons why one may still want a refresh token:
as the OP mentions the user might see a few redirects and both the UI expert and the branding guy on your team will hate this
when an access token expires in the middle of an HTML Form POST action, the redirect may have lost the context/POST-data on return; you may want to minimize this or you'll have to take appropriate (complex) POST-data-save actions
if your access token expiry is really short, the redirects create a lot of overhead and nuisance; you may not be able to control access token expiry when dealing a Providers in a different domain and when dealing with multiple Providers it will vary across them
when refreshing the access token with a redirect your application now depends on the Provider keeping an SSO session; not all Providers may do this and if they do they may do it in different ways: the SSO session duration may vary between them and the authentication method may vary; as an example: a Provider that doesn't keep an SSO session but does use 2-factor authentication will have large impact on the user experience
Imagine a scenario where you want to use the access token to update user information in almost real-time from the user info endpoint but the access token expiry is relatively short. Either you'll have to perform a lot of redirects with the nuisance as described, or you can use a refresh token.
Refresh token is essentialy a credential reference, that your client can exchange for access token, when there is no active user session.
For example if you want to periodicaly sync issues from Github with your inhouse system.
It is often misused like some kind of session. It is essential to diffirentiate those things. And scope name offline_access is there for a reason.
So in simple cases - you just rely on OP session and get new token with authorize/token endpoints combo. You should not be prompted to provide credentials as long as session is alive and consent is given for that particular app.
If you need to do some backgound stuff - ask for refresh token also.
As for question: no.
EDIT(More in-depth explanation):
if we are talking about web there are two main cases:
Client that can securely store secrets like usual web app with server page rendering and clients, that cant store secrets, like SPA apps. From that perspective there are two main flows (omitting hybrid to not over-complicate): Authorization Code Flow and Implicit Flow respectively.
Authorization Code Flow
On first request your app checks it own session(client session) and if there is none - redirects to external OP(OpenID Connect provider) authorize url. OP authenticates user according to requirements expressed in request, gathers consent and other stuff and returns authorization code. Then client asks token endpoint with it and receives access_token/id_token pair with optional refresh token if user granted offline access consent. This is important, because user can deny it for your app. After this client can request userInfo endpoint to get all user claims that were granted during consent. Those claims represent user identity and do not contain stuff like authentication method, acr etc. Those claims present in id_token alongside with expiration for example. After that client starts it own session and have option to set its lifetime equal to id_token lifetime or use it own to provide smooth UX for example. At this point you can discard access_token and id_token at all if you don't need access to other APIs(like all scopes in access_token are specific to OP and subject). If you need access to some API you can store access_token and use it for access. It becomes invalid - redirect to OP for new one. Expiration can be more lax here, because of more secure environment on server. So even 1hr is an option. No refresh tokens used at all.
Implicit Flow
In this case your lets say Angular app redirects to OP, gets its id_token and optional access_token from authorize endpoint directly and uses it to access some APIs. On every request expiration is checked an if needed, client sends request to OP in hidden iFrame, so there won't be any visible redirects as long as OP session is alive. There are some great libs for that like openid-client.js. No refresh is allowed here at all.
It is important to differentiate client session from OP session, token lifetime and session lifetime.
To address some specific needs there is Hybrid Flow. It can be used to get authorization code and id_token for your session in one request. No chit chat over network.
So when you think about refresh token just check your needs and map them to a spec :) And if you need it anyway - store it as secure as you can.
Refresh tokens are useful for applications that keep access tokens in a server session. For example if a web application doesn't call a protected service using JavaScript XHR, but calls its backend and the backend calls the service. In this scenario, it's easier to get a new access token whenever it's needed than asking a user for a new one.
In JavaScript applications running in browsers, refresh tokens cannot be used, because you need a client secret to get an access token from the /token endpoint and you cannot keep the secret safe in such applications.
The process for getting new access tokens you described can be improved - an application may ask for a new access token just before the current one expires, so the user doesn't get redirected to the OAuth2 server, but the application calls the /auth endpoint with prompt=none parameter in an iframe.
I am facing a custom implementation of OpenId Connect. But (there is always a but) I have some doubts:
I understand the process of obtainning an acces_token an a id_token, except the step when the OP provides an authorization_code to the client. If it is done by a redirect (using the redirect uri)
HTTP/1.1 302 Found
Location: https://client.example.org/cb?
code=SplxlOBeZQQYbYS6WxSbIA
&state=af0ifjsldkj
The end-user is able to see that authorization code? It does not expire? Imagine we catch it and we use later (some days later) Is it a security hole? Should the state be expired in the Token Endpoint?
The flow continues and we got at the client the Access_token and the id_token in the client.
How the Access_token should be used on the OP side ? It should be stored in a database? Or be self containing of the information required to validate it ?What would you recommend?
And in the client-side , both tokens should be sent in every request?
And the last doubt, if we have an Access_token the existence of an id_token is for representing authorization and authentication in separated tokens?
Extra doubts:
I know the process to obtain an access token but I have doubts of how the OP ,once generated and sent, it validates the access_token that comes with every request
How the OP knows an access token is valid? As far as I know, the OP should say that an access_token is valid/invalid. There should be some way to check it right? How it gets to know that a token represents a valid authenticated user if it is not stored in DB?
Is it a bad idea to store access_token in a cookie? Because sometimes we call to some webservices and we want to send access_token as parameter. Or there is another workaroundsolution?
How the access token should be stored in the Client , for example, in ASP.NET, in the session?
Thanks very much to all of you, I will give upvote and mark as answer as soon as you give me the explanations.
Thanks!
The end-user is able to see that authorization code?
Yes. Although, even if the authorization code can be seen, the token request requires that the client's secret be sent as well (which the browser does not see)
it does not expires? Imagine we catch it and we use later (some days later) It is a security hole? Should the state be expired in the Token Endpoint?
The spec says that the authorization code should expire. See https://www.rfc-editor.org/rfc/rfc6749#section-4.1.2.
How the Access_token should be used on the OP side ? It should be stored in a database? Or be self containing of the information required to validate it ?What would you recommend?
The access token should be stored on the OP if you want to be able to revoke the tokens. If you don't, the token will be in JWT format (self-contained)...but you should store it if you want to be able to revoke it whether it's a JWT or not.
And in the client-side , both tokens should be sent in every request?
No, just the access token.
And the last doubt, if we have an Access_token the existance of an id_token is for representing authorization and authentication in separeted tokens?
Yes, they are separate tokens for different purposes. Access token is for authorization and Id token is self contained and used to communicate to the client that the user is authenticated.
How the OP knows an access token is valid? As far as i know, the OP should say that an access_token is valid/invalid. There should be some way to check it right? How it gets to know that a token represents a valid authenticated user if it is not stored in DB?
see How to validate an OAuth 2.0 access token for a resource server? about thoughts on how the resource server should validate the access token before letting the request from the client go through.
It´s a bad idea to store access_token in a cookie? because sometimes we call to some webservices and we want to send access_token as parameter. Or there is another workaroundsolution?
I'm assuming you're using the authorization code grant flow (...from your questions). If that's the case, the reason why an authorization code is, first of all, passed back from the OP rather than the access token is so that the access token can stay hidden on the server side--away from the browser itself. With the authorization code grant flow, the access token should stay out of the browser. If you're wanting to send api requests to the resource server directly from the browser, then look into the oauth2 implicit flow (https://www.rfc-editor.org/rfc/rfc6749#section-4.2).
How the access token should be stored in the Client , for example, in ASP.NET, in the session?
In the OpenID Connect flavour of OAuth2, the access token is for offline_access (i.e. outside of an authenticated "session"). The access token could be used during the session of the user but it might be better to store the refresh token in the database so that your client app can request new access tokens whenever it needs to and as long as the refresh token is valid...even when the user's authentication is expired. The access token should be short-lived so storing it in the database is an option but not necessary.
When implementing the OAuth2 protocol, is it possible to pass authorization to a second client, similar to proxy authentication in CAS?
The user is authenticates with a client web site, which has been granted authorization to access that user's account, that gives access (passing the token or whatever) to another client. Is that possible? Do I need to have the user authorize it separately? Can I pass a refresh token to the applet?
The access token returned from an OAuth dance is sometimes called a "bearer token", which belies the fact that whoever or whatever has it is considered authenticated and authorized to access resources. You can, for example, get an access token using the JavaScript flow and pass it up to a server to make requests. Or vice versa. Access tokens are access. So in that way, access is portable. But access tokens generally expire after some amount of time.
The refresh token on the other hand does not expire, but is generally tied to a callback URL. Exchanging a refresh token for an access token generally requires the callback request to be sent to a whitelisted set of URLs. So you can't generally pass a refresh token around effectively. (Note: That doesn't mean you shouldn't be careful with it, it's still essentially a scoped password, and you definitely want to keep it private).