I am not clear on what exactly I should do with the id token from Google after the initial verification.
I'm developing on expo/react native and get the id token locally. Then, I send it to my server and verify it using google client libraries. Once it's verified what should I do with it?
Ideally I could use it to protect my api routes (express) but id tokens expire after 1 hour and I'm not sure how to refresh them with the client library. So, I don't know how I would do this.
Is that the intended use for id tokens? Should I instead be signing my own jwt and sending that back to the client? Then, the client could send that in the auth header of each request to a protected routes.
Google says:
After you have verified the token, check if the user is already in your user database. If so, establish an authenticated session for the user. If the user isn't yet in your user database, create a new user record from the information in the ID token payload, and establish a session for the user. You can prompt the user for any additional profile information you require when you detect a newly created user in your app.
https://developers.google.com/identity/sign-in/ios/backend-auth
Do I use the id token to "establish a session for the user"?
Yes, the ID-token is only used to create the local session, perhaps also create a local entry in your local database if that is used.
The ID token also have a very short lifetime, like 5 minutes in some systems. So it has no long-term use.
The ID token is intended to authenticate the user. It gives you information about the authenticated user, it should not be used to allow access to your endpoints. Access tokens or sessions are intended to do so. So in your case, you should do exactly as your gut feeling tells you - create a session for the user basing on the data you got in the ID token.
If you have your own Authorization Server you can use the ID token to issue an access token and return the token to the frontend app, then use the access token to access your backends. Have a look at OAuth flows if you would want to go this way.
I'm following this article to understand refesh tokens.
In my case I have to connect to REST api using grant_type=password, and I receive a token with a 5 minute lifespan. So every 5 minutes I have to issue a POST request passing client-id, username & password to get a new acces token.
The other option would be to issue a POST with a grant_type=refresh_token, without having to send the username & password. In my case I'm consuming an api, so passing the credentials doesn't involve any action from the final user. For me it's just to params more to send on the POST request.
In both cases, I have to issue a new post every 5 minutes.
Is that the only advantage (not needing to pass credentials again) of using the reresh token or is there any other thing I'm missing?
Background info
OAuth 2.0 Password Grant
The Password grant type is a way to exchange a user's credentials for an access token. Because the client application has to collect the user's password and send it to the authorization server, it is not recommended that this grant be used at all anymore.
OAuth 2.0 Refresh Token
The Refresh Token grant type is used by clients to exchange a refresh token for an access token when the access token has expired.
This allows clients to continue to have a valid access token without further interaction with the user.
Consider this.
Lets say that i add my login and password for my twitter account to your application and you then use that to request access from twitter to may account to post. Three months later i have forgotten i have set your awesome app up to do something on my twitter account and i change my password. Your system will break.
Now lets say i used Oauth2 to grant you access to my Google drive account, your awesome app can now do what ever it needs to do on my drive account. Now three months latter i have again forgotten i gave your awesome app access, I have the memory of a gold fish you see. I change my password. Nothing happens your awesome app still has access.
Now consider this, With oauth2 i can grant you access to only read from my google drive account not update it (scope). That and the system knows its not actually me preforming the actions.
With client login (login and password) most of the time it appears to the system that it is the actually owner of the account making the requests. You can also not limit access with client login for the most part you have full access.
note
yes i am ignoring the part about both tokens returned being the expiration time time. Thats because for all intensive purposes they are the same but that depends greatly on how the auth server you are using is set up. They could be set up to only be valid for an hour or a day. They may give you different access scopes, again this differs greatly from auth server to auth server.
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!
I am trying to impliment Oauth for my webapplication for google.I am worked upon a POC and it working fine but i have a confusion and not sure how best it can be achieved.
I am using scribe java API for Oauth.
here are the steps i am performing.
Getting request token from Google.
Redirecting user to Google to authenticate them self and authorize my serivice to access his/her few details.
get Access Toekn from google by providing request token and verification code given by google.
Accessing user info once google provide Access token.
now my main confusion is at step no 3, since i am working on a web-application so it will be a 2 step process.
Redirecting user to google
Handling back google redirect.
In order to get an Access token i need to provide same request token which i got at step1 else my request being rejected by the user.
The request token contains 2 things
Toekn -->which is based on the registered application so not an issue
Secret-->This is always being a random string so it should be same when asking for access token
that means i need to store this secret either in my session or some where so that i can access this secret when user is being redirected back to my application.
My confusion is,since in order to save it in session i have to create a unique key and some way to access it in the other action class which will handle Google Redirect back how can i achieve this since at a given time so many user can ask to login using google.
any help in this regard will be much appriciated.
Thanks in advance
When you receive the request token + token secret, use the request token as the unique key of your session to store the token information. After the authorization process, in the callback url, you have access to the request token (it's one of the parameters passed to the callback url). Using this parameter as the session key, you can restore the token information from session, including the token secret, and use it to sign your request for changing the request token for access token. After receiving the access token, a new token secret is returned to you and you can delete the old one from session.
how can i achieve this since at a given time so many user can ask to
login using google
This is not of any problem because for every single user on your site, you are given a different request token.
After a real brain bending session today I feel like I understand 3-legged OAuth authentication fairly well. What I'm still having trouble understanding is the use of the User ID. The examples I have seen so far all seem to just arbitrarily assign a user ID at the top of the sample script and go. That confuses me.
Most of the sample code I have seen seems to center around the concept of using a user ID and the OAuth server's consumer key for managing an OAuth "session" (in quotes because I'm not trying to conflate the term with a browser "session"). For example, the database sample code I've seen stores and retrieves the tokens and other information involved based on the user ID and consumer key field values.
I am now in that state of uncertainty where a few competing fragments of understanding are competing and conflicting:
1) If my understanding of the OAuth session details record or "OAuth store" lookups is correct, via the consumer key and user ID fields, then doesn't that mandate that I have a disparate user ID for each user using my application that connects with an OAuth server?
2) If #1 is correct, then how do I avoid having to create my own user accounts for different users, something I am trying to avoid? I am trying to write software that acts as a front end for an OAuth enabled service, so I don't need to have my own user records and the concomitant maintenance headaches. Instead I'll just let the OAuth server handle that end of the puzzle. However, it seems to follow that the downside of my approach would be that I'd have to reauthorize the user every session, since without my own persistent user account/ID I could not lookup a previously granted "good to revoked" access token, correct?
3) What bothers me is that I have read about some OAuth servers not permitting the passing of a dynamically specified callback URL during the requesting of the unauthorized token, making the passing of a consumer key and a user ID back to yourself impossible. Instead you specify the callback URL when you register as a developer/consumer and that's that. Fortunately the OAuth server I'm dealing with does allow that feature, but still, if I was dealing with one that wasn't, wouldn't that throw a giant monkey wrench into the whole idea of using the consumer key and user id pair to index the OAuth session details?
This is an answer to the question by Lode:
Is it correct that not only the provider needs to have user ids (that sounds logical) but also the client? So the client (using OAuth as a login system) needs to create a user (with an ID) before successfully authenticating them via the OAuth server. Making you have a lot of empty user accounts when authentication fails or access is not granted.
It's possible to use OAuth for authentication of users without having local accounts at the consumer application, but you've got to have some kind of session mechanism (cookies/get params) in order to have some internal session representation in which you would store the oauth_token.
For example, if someone has landed to your web application, and your application is a consumer of some OAuth provider, you will have to create a local session at your site for the end-user: for example with a cookie. Then you send the end-user to the OAuth provider for authorization of a token, so that your application can get protected resources from the provider. Currently you know nothing about the user and you don't care about his identity. You just want to use some protected information from the provider.
When the user comes back from the provider after successful authorization and brings back the oauth_token, you now have to store this token in the session that you previously created for the user. As long as you keep your session (and the token if it's needed for further requests for resources), you can consider that the end-user is logged in. In the moment that you delete his session or the token expires, you can consider him no more logged-in. This way you don't have to make your own users DB table or storage mechanism.
However, if you need to have some persistent information about the users in your application, that will be used between user sessions (logins), you have to maintain your own users in order to know with which user to associate the information.
As for the difference between openid and oauth - from the perspective of local accounts, there is no difference. It's all the same. The difference is only that with openid you receive immediately some basic user info (email, etc.) while with oauth you receive a token and you have to make one more request to get the basic user info (email, etc.)
There is no difference however in regard to local accounts, if you're going to use OpenID or OAuth.
I will try to tell my view on the issues that you raised and hope that will clear things a little bit...
First, the idea is that the OAuth server is protecting some API or DATA, which third party applications (consumers) want to access.
If you do not have user accounts or data at your API behind the OAuth server, then why would a consumer application want to use your service - what is it going to get from you? That being said, I can't imagine a scenario, where you have an OAuth server and you don't have user accounts behind it.
If you just want to use OAuth for login of users, without providing user data through API, then it's better to use OpenID, but again you will have to have user accounts at your side.
Your point is correct that you make lookups via Consumer Key and (Your) User ID, and that is because of the protocol design.
The general flow is:
OAuth server (Provider) issues unauthorized Request Token to consumer application
Consumer sends the end-user to authorize the Request Token at the OAuth server (Provider)
After end-user authorizes the token, an access token is issued and given to the consumer (I've skipped some details and steps here, as they are not important for what I want to say, e.g. the consumer receives valid access token at the end)
On the authorization step, it's your OAuth server that create and save as a pair - which local user (local for the provider) authorized which consumer (consumer key-user id pair).
After that, when the consumer application want to access end-users DATA or API from Provider, it just sends the access token, but no user details.
The OAuth server (Provider) then, can check by the token, which is the local USER ID that has authorized that token before that, in order to return user data or API functionallity for that user to the consumer.
I don't think that you can go without local users at your side, if you are a provider.
About the callback question, I think there's no difference if you have dynamic or static (on registration) callback URL in regard to how you handle OAuth sessions with consumer keys and user id. The OAuth specification itself, does not mandate to have a callback URL at all - it's an optional parameter to have, optional to send every time, or optional to register it only once in the beginning. The OAuth providers decide which option is best for them to use, and that's why there are different implementations.
When the provider has a static defined callback URL in the database, connected with a consumer, it is considered a more secure approach, because the end-user cannot be redirected to a 'false' callback URL.
For example, if an evil man steals the consumer key of a GreatApp, then he can make himself a consumer EvilApp that can impersonate the original GreatApp and send requests to the OAuth server as it was the original. However, if the OAuth server only allows static (predefined) callback URL, the requests of the EvilApp will always end at the GreatApp callback URL, and the EvilApp will not be able to get Access Token.