OpenId Connect Questions -Authorization Code Flow (OAuth 2.0) - oauth

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.

Related

Oauth 2: why refresh tokens must be stateful?

I'm working on a SPA app based on Node, with token-based authentication using JWT. Right now, the jwt token never expires, which is not good.
I want it to expire for more security, but I don't want my users to be forced to re-log. That's why I need a refresh token.
So i'm reading about OAuth2.
I have a hard-time to understand why refresh-tokens must be stored in a database, whereas access-token are generated on the fly using a secret key.
Why refresh tokens can't be generated the same way as access tokens ?
Thank you guys !
Refresh tokens usually are generated the same way as access tokens.
An authorization server will often return a refresh and access token if requested (and you're not using the implicit grant type).
The difference is how they are used.
An access-token is usually a bearer token: whoever has it can use it against the resource server, but it is only valid for a short period of time. In which case, storing them in a database is often pointless as they are worthless once expired.
A refresh token however is like having access to a "forge" which allows you to mint a new token.
If you present the refresh token to the authorisation server (not the resource server) you will get back a new access token and possibly a new refresh token.
Providing of course that the user has not revoked/changed access permissions to your application and that the user is still a valid user.
So you would keep them in a database perhaps because your user logs in infrequently. So you may need the refresh token weeks after you got it.
Alternative to the refresh token.
If you are using the implicit grant (which is common with SPAs but not recommended). You can try and keep your end user logged in to the identity provider used by the authorisation server. This way you can keep requesting new access tokens from the auth server without the user being prompted by the auth server for credentials as a session will be persisted between the identity provider and the user's browser.

OAuth2 refresh token utility

I'm reading through the OAuth2 RFC 6749 specs before implementing an Authorization/Resource server for the Resource Owner Password Credentials Grant.
I understand that the Client application uses the refresh_token (along with its credentials) to obtain a new access token for an End User (Resource Owner) rather than storing the End User's username/password and sending them every time an access_token expires.
However, to me this sounds like the refresh_token is as good as an access_token, it's pretty much just an extra server call, so why not use it directly i.e. if the refresh token is valid grant access?
Am I also correct to assume there is one refresh token per End User's session?
However, to me this sounds like the refresh_token is as good as an
access_token, it's pretty much just an extra server call, so why not
use it directly i.e. if the refresh token is valid grant access?
Because that extra server call to the Authorisation Server is important in ensuring access is still allowed to the client app. The resource server would not be able to verify that the refresh token is still good without talking to the Authorisation Server. But this is not the concern of the resource server.
A valid access token is a bearer token. It is used directly on the resource server to get data - no questions asked. If it's not expired, and it has the right scopes - here's the data, whoever you are!
A refresh token on the other hand has to be presented to the Authorisation Server along with client credentials. The Authorisation Server may choose to verify that the resource owner hasn't revoked access to that client, or that the client app itself is still valid. If OK the authorisation server can mint a new, short-lived bearer access token, which is as good as data to anyone who has it!

Partial Authentication after expired token

I'm fairly new to Oauth and I am wondering if a specific flow is supported by any of the Oauth flows. I want to be able to identify a user and allow that user to perform unsecure actions even after their token has expired. The user would only be forced to reauthenticate if they request to perform a secure operation. I currently do not see any flow that will support this.
I have thought of the following solution using refresh tokens but not sure I am possibly violating any oauth patterns or if there is a better way.
1) Issue access token for X amount of time. Lets say 2 hours.
2) Upon token expiration, refresh token is used to get a new access token. The new token will contain a claim that identifies that the user only has unsecure access.
3) If secure resource is requested, request will be denied with a 401 response code indicating that the token is invalid.
4) Application will have to ask for user credentials in order to receive a new access token.
Any thoughts on this?
This is really up to the interaction between the Resource Server and the Client and certainly with the boundaries of standard OAuth 2.0 . The only thing that OAuth 2.0 standardizes in that interaction is the way in which the access token is presented. All other behavior is left up to the application implementor.
The Resource Server would allow access to unsecure resources/operations regardless of the validity of the access token, or even if there's no access token presented at all. Only upon accessing a secured resource the flow would would as you describe.
I don't see value in producing access tokens that identifies "unsecure access". That token would have the same semantics as an expired token or no token at all, so there's no need for an access token to cover that case.

What is intent of ID Token expiry time in OpenID Connect?

In OpenID Connect an access token has an expiry time. For authorization code flow, this is typically short (eg 20 minutes) after which you use the refresh token to request a new access token.
The ID token also has an expiry time. My question is what is the intent of this?
Any ID token expiry time less than the expiry time of the refresh token will mean you will eventually have an expired ID token, but a valid access token.
So are you meant to:
give your ID token an expiry longer than the refresh token expiry, or
set it to the same expiry as the access token and take some action (what?) when it expires, or
just consume the ID token in your client on receipt, then ignore the expiry time after that?
The OpenID Connect specification just says that when validating an ID token,
"The current time MUST be before the time represented by the exp Claim."
which (possibly) supports the third option above.
EDIT
As OpenID Connect builds on OAuth2 the answer to the supplementary question below can be found in the OAuth2 specification which says,
expires_in
RECOMMENDED. The lifetime in seconds of the access token.
A related question is when you exchange an authorization code for the tokens, the same specification says you might get a response such as:
{
"access_token": "SlAV32hkKG",
"token_type": "Bearer",
"refresh_token": "8xLOxBtZp8",
"expires_in": 3600,
"id_token": "eyJhbG[...]"
}
But what does "expires_in" relate to in this case? The access token, the refresh token or the ID token?
(For information, IdentityServer3 sets this to the access token expiry time).
I'm answering my own question as have discovered that some of the assumptions behind my question were wrong, so easier to clarify here, rather than re-write the question.
An ID token is meant for proving to a Client that the user has authenticated, and who they are as a result.
When a Client receives an ID token, it will generally do something like convert it to a ClaimsIdentity, and persist this, eg using a cookie.
The ID token has to be un-expired at this point of use (which it should be, since it has just been issued). But after this it is not used again, so it does not matter if it expires while the user still has an active session. The Client has the authentication information it needs, and in turn can choose its own policy for how long the session lasts before the user has to log in again.
My wrong assumption when asking the question was that an ID token and access token should be used together, and therefore both needed to have valid expiry dates. This is wrong for various reasons:
ID tokens are only for authenticating to a Client (as described above).
Access tokens have nothing to do with Clients. They are for access to resources and a Client only handles them if it in turn needs to call an resource.
Something like a standalone MVC or WebForms application only needs an ID token. If it isn't calling an external resource, there is nothing to grant access to, so no access token.
I had to dig into this for my own reasons and wrote it up, so I'll post what I learned here...
First, I'll answer the question at the risk of stating the obvious: The ID token cannot be trusted and its content must be ignored if the current time is greater than the expired time. The questioner's answer states that the after the initial authentication of the user, the ID Token isn't used again. However, since the ID Token is signed by the identity provider, it certainly could be useful at any time to give a way of reliably determining who the user is to other services that an app might be using. Using a simple user ID or email address isn't reliable because it can be easily spoofed (anyone can send an email address or user ID), but since an OIDC ID Token is signed by the Authorization server (which also usually has the benefit of being a third party) it cannot be spoofed and is a much more reliable authentication mechanism.
For example, a mobile app may want to be able to tell a backend service who the user is that is using the app and it may need to do so after the brief period following the initial authentication, at which time the ID Token is expired, and thus, cannot be used to reliably authenticate the user.
Therefore, just like the access token (used for authorization - specifying what permissions the user has) can be refreshed, can you refresh the ID Token (used for authentication - specifying who the user is)? According to the OIDC specification, the answer isn't obvious. In OIDC/OAuth there are three "flows" for getting tokens, The Authorization Code flow, the Implicit flow, and the Hybrid flow (which I'll skip below because it's a variant of the other two).
For the implicit flow in OIDC/OAuth you request the ID Token at the authorization endpoint by redirecting the user in the browser to the Authorization endpoint and including id_token as the value of the response_type request parameter. An Implicit Flow Successful Authentication Response is REQUIRED to include the id_token.
For the Authentication Code flow, the client specifies code as the value of the response_type request parameter when redirecting the user to the authorization endpoint. A successful response includes an authorization code. The client client makes a request to the token endpoint with the authorization code and, according to OIDC Core Section 3.1.3.3 Successful Token Response the response MUST include an ID Token.
So for either flow, that's how you initially get the ID Token, but how do you refresh it? OIDC Section 12: Using Refresh Tokens has the following statement about the Refresh Token Response:
Upon successful validation of the Refresh Token, the response body is the Token Response of Section 3.1.3.3 except that it might not contain an id_token.
It might not contain an ID Token and since there is no way specified to force it to include the ID token, you must assume that the response will not contain the ID Token. So technically there is no specified way to "refresh" an ID Token using a refresh token. Therefore, the only way to get a new ID Token is to re-authorize/authenticate the user by redirecting the user to the authorization endpoint and starting the implicit flow or authentication code flow as described above. The OIDC specification does add a prompt request parameter to the authorization request so the client can request that the authorization server not prompt the user with any UI, but the the redirect still has to happen.
If I understand correctly, according to this and the OpenID Connect Core 1.0 spec, the ID token itself can be stored in cookies as a mechanism to persist sessions, and sent with every authentication-requiring request to the Client. The Client can then verify the ID token either locally or through the Provider's verifier endpoint (if provided, like Google does). If the token is expired, it should make another auth request, except this time with prompt=none in the URL parameter. Also make sure to send the expired ID token in the id_token_hint parameter, otherwise the Provider may return an error.
So, it does seem natural for the ID Token to expire, but prompt=none ensures the new ID token can be obtained smoothly with no user intervention (unless of course the user is logged out of that OpenID).
It is the same intent: you can't use the id_token after it is expired. The main difference is that an id_token is a data structure and you won't need to call any servers or endpoints, as the information is encoded in the token itself. A regular access_token is usually an opaque artifact (like a GUID).
The consumer of the id_token must always verify the (time) validity of it.
I'm not 100% familiar with IS, but I would guess it is a convenience field. You should always check the exp claim.
Expiration is just one of the validations. id_tokens are also digitally signed and that is also a validation you must perform.
Refreshing a token means that you can use it again for requesting something from the authorization server (in this case the OP - the OpenID-Connect Provider) EVEN WHEN THE USER IS NOT LOGGED IN. You typically allow this for limited resources only, and only after the user has logged in and been authenticated at least once. The refresh tokens themselves should be also limited in time.
In OIDC implicit flow you call the Authorization endpoint,
and receive the ID token in the response along with all the scopes and in them all the claims info.
Subsequent calls to an API are meant to be done with code flow.
Implicit flow is meant to enable a javascript only or browser only app. Not an app that is interacting with a server.
So even if there was a way to "refresh" this token, you should not - security wise - allow it to live too long. It will be stolen and reused by unauthorized users impersonating the id. You should force a new login for that.
In code flow you call the OP's Authorization endpoint, and receive an Authorization code (also called an authorization token, or authcode for short). This should expire similar to the id_token that you received in implicit flow, for the same reasons and cannot and should not be renewed.
Your UI or app then call the OP's Token endpoint, and receives (sometimes after the user's further consent through a UI to allow use of their owned resources on the OP's server) both:
An id_token, for authentication - which should never be used again in server calls, except as a hint during logout, when its expiration is not important anymore, and so, for the reasons above should be let to expire, and never be refreshed.
An access_token - which later on, when calling an API, can be given to the OP's UserInfo endpoint. That will return the claims, and the API can authorize accordingly.
You can refresh this access_token, since it only tells the API what claims the user has, and what resources (by scopes and each scope's claims) the user agreed to give you. As explained above this is for allowing access even after the user is not logged in anymore. Of course you never wish to allow the id_token to be refreshed, because you don't want to allow impersonation without logging in.
I wanted to post this answer as a comment but since I haven't been very active on StackOverflow, I guess I'm posting it as an alternate answer.
You also use id_token as the id_token_hint when attempting to log the user out of a session http://openid.net/specs/openid-connect-session-1_0.html. I honestly don't think that it really matters if the id_token is expired at this point since you're only concerned about logging out a particular user.
TLDR;
Validate the ID token before trusting what it says.
More Details
What is intent of ID token expiry time in OpenID Connect?
The intent is to allow the client to validate the ID token, and the client must validate the ID token before operations that use the ID token's information.
From the OpenID Implicit Flow spec:
If any of the validation procedures defined in this document fail, any operations requiring the information that failed to correctly validate MUST be aborted and the information that failed to validate MUST NOT be used.
To corroborate that, Google's OpenID Connect documentation says this about ID token validation:
One thing that makes ID tokens useful is that fact that you can pass them around different components of your app. These components can use an ID token as a lightweight authentication mechanism authenticating the app and the user. But before you can use the information in the ID token or rely on it as an assertion that the user has authenticated, you must validate it.
So, if our client application is going to take some action based on the content of the ID token, then we must again validate the ID token.
Just share my journey. It's June, 2021. I'm writing this because I've stumbled into 3rd-party authentication business. I'm a veteran programmer but novice to security. In other words, all standards, spec, and terminologies are strangers, anybody can beat me in this field. Forgive me for not going by all the terms.
Cut to chase, I'm writing an Angular/Node app, so UI=Angular, API (API server)=Node/Express. Instead of creating my own Username/Password authentication, I'm turning to 3rd-party authentication, let them validate the genuineness of what the users claim they are. Here are two important guidebooks for me:
Angular Authentication With JSON Web Tokens (JWT): The Complete Guide
Eiji's Authenticate with a backend server
Combining No. 1 and angularx-social-login, I have the UI hooked up with Google, then attach idToken to API, vola! Following No. 2 using local library API can validate idToken, great!
Wait, idToken has exp expires in 1-hour. How do I refresh it?
My understanding is all I need is Google's authentication, I don't care what standard and version they use, but like others I just trust their authentication. Authentication is basically verify who they claim they are. Authorization is access control for what/where users can do/goto. The internal access control (allow users to do what) is not exposed to Google they have no idea of it. So accessToken should be out of the picture. Right?
I've spent days studying on how to refresh idToken now concluded Google does not recommend it nor angularx-social-login offers a way. In No. 2, Eiji has stated clearly:
Hence, solution for my situation is
use Google's authentication.
creates an own session management/timeout-rules at API after initial validation of idToken to mitigate exp.
preferably add this session data into cookie with res.cookie("SESSIONID", myOwnID, {httpOnly:true, secure:true});
For better protection, Eiji also recommends Cross Account Protection. Hope this will help someone!

oAuth2.0 access token confusion

I am following this tutorial about OAuth2.0 https://developers.google.com/youtube/v3/guides/authentication
It looks quite clear how OAuth2.0 works. But I have a bit confusion at the access token part.
After obtaining an access token for a user, your application can use
that token to submit authorized API requests on that user's behalf.
The API supports two ways to specify an access token: Specify the
access token as the value of the access_token query parameter:
www.googleapis.com/youtube/v3/videos?access_token=ACCESS_TOKEN
if someone acquired this access token during the url transferring they can access this protected resource right?
How the server know if the request is coming from the client initially requested the access token?
UPDATE:
after reading this post Are HTTPS headers encrypted? my confusion is cleared. I thought query string is not encrypted during transmission in the network.
Generally I think the consensus is that OAuth 2.0 is a server side technology and all access tokens and communication should be transmitted using SSL as the bearer tokens need to be kept as secure as possible.
Also, you need to know that there are 2 types of flows in OAuth 2.0
i) Implicit grant flow - This is the flow where the user logs in to the service provider and his browser gets the access token. Say you have X.com and Log in via Facebook. Once the user keys in his FB credentials, the access token is sent to his browser.
ii) Authorization Code flow - In this flow (consider the above situation again), facebook will pass an authorization code to the user's browser. If anyone, somehow, intercepts the authorization code there is nothing he can do. An authorization code can be exchanged for an access when passed with valid client credentials. So, when the user logs in, his browser gets an authorization code which is passed to your server at X.com. from there you would hit the code-token exchange endpoint provided by FB and get the access token returned to your server!
Authorization code flow adds another layer of security, where the access token is visible only to the client + server and not to the user agent. And as you figured out yourself, the token is passed via HTTPS.

Resources