AbstractAuthorizationCode Servlet & CallbackServlet - how to implement getUserId()? - oauth-2.0

How to correctly implement abstract getUserId(request) method in these Google OAuth2 abstract servlets?
As code says, it is used to lookup and store google credential. I've seen example which returns session id, but that won't work correctly after session expiration:
User visits auth url, his access and refresh token are stored in storage under sessionId key
Within session lifetime, everythings works fine, so if this user visits auth url again, his stored tokens are found with the same sessionId key
But after session expiration (server restart etc) when this user visits auth url again, he gets new sessionId, no stored tokens are found, so new tokens (this time only access token) are requested and stored again under new sessionId key
So the question is - how to generate userId that will work in all cases? GoogleAppEngine implementation uses logged user, which is perfectly fine - but how do I generate such userId from just HttpRequest parameter?
BTW this (https://developers.google.com/gmail/api/auth/web-server) python implementation seems to generates parallel userinfo request to get user email manually...

First, make sure you need offline access to the user's credentials.
The reason all of these examples you cite use logged in user is because the user id is necessary to store the credentials against the correct user in the credential store.
In those use cases, Google OAuth is used to authorize the web server to undertake some action in the user's Google account.
One idea for user id to create a long lived coookie (using secure random generator) and use that to identify the user, so you know who they are when the visit the site again, and can reuse the credential (if you asked for offline access). This is not very robust, as the user can clear their cookies, but there is no other way short of logging the user in.
(Yes, Google Oauth can be used to log in the user, but you are still looking at a sending the user to Google every time, so you really gain nothing by doing that).

Related

How should I use the id token returned to me by Google after a successful code exchange?

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.

Using a third party site for OAuth2 / OIDC authorization code flow- understanding the final steps

I've a site which will hopefully use a third party service for logging in (through use of OAuth2 and OIDC). I understand 90% of the process involved but am failing to get what I see as the final step. I'll describe the steps as I see them here and maybe someone can help me fill in the gaps. In my set up the Resource Server and Authorisation servers are the same machine.
This is the login process as I envisage it.
User comes to my site (let's call it Site A) and clicks login
They're redirected to the authentication site (Site B) where they
input their username / password.
Assuming correct credentials they're then redirected back to Site A with an auth code.
Site A takes this auth code and in a back channel communicates with Site B
again asking to exchange the code for a token.
Site B provides an access token to Site A (not to the end user, to the server)
Site A then communicates with Site B again (Resource and Authentication servers are the same in this scenario) and gets the relevant user detail.
So the user is authenticated and we know what claims they have, however, what I don't get in the above scenario is how Site A knows who I (the end user) am.
I never logged in on Site A so presumably no cookie was set. Basically I've gone to the site, been redirected to another site, logged in there and then am redirected back to Site A but is there a cookie set at that last redirect to identify me?
I've read plenty about this online but haven't found a clear answer.
Also, am I correct in thinking that in authorization code flow that the access token never gets to the user but instead resides on the application server?
If you really want to know who the user is on SiteA, it has to be the user from SiteA's own user database. It makes sense if SiteA is not just a proxy for SiteB's API and has its own users, permissions and functionality.
To figure out who the user is on SiteA you will need to match all your SiteA's users with Auth Server's users.
Part 1. Import your existing users into Auth Server
If you control Auth Server, import all your current users into its user database. Every one of them will have Subject ID (Id on Auth Server side). Copy those IDs back to corresponding users in your SiteA's db: your SiteA's User table will have new column, for example:
userid, user_name, user_last_name, user_auth_id (new column)
if you can't import all your users, it gets complicated. The only way I can think of: you will have to log those users in twice - once into OIDC provider and once in SiteA and then associate SiteA's user with OIDC user.
Part 2. Matching the incoming user to the internal user in SiteA
In successful response from OIDC Server you will get ID Token back. It contains sub claim with Subject ID of the user. When you've got that, you will need to do a lookup in your internal DB and find a corresponding SiteA's user. If you did not find one, create a new user at SiteA (if all existing users had been imported)
Once you know who the user is, log them in to SiteA like you would normally do (give them a cookie for example).
OpenID Connect auth servers provide the userinfo endpoint, which Site A can use for getting info about the user who authorized the access token (or the authorization code). For the auth provider (Site B) to be able to do it, it needs to keep association between a token and its user. So there is no cookie for this purpose.
You are correct about the auth code flow - the access token stays at the backend - there is no need to send it to the frontend / user.
To be able to pair the tokens kept at the SiteA backend with the consequent requests from the browser, you have few options:
You can use a backend session with cookies, which is very easy, because most backend frameworks have a built-in support for it. The cookie is sent automatically with each request and the tokens can be stored in a session object. This solution may be harder to scale - if you need a cluster.
You can create your own session implementation - either by using cookies or by some identifier expected on REST API as the Authorization HTTP header value. The backend session data can be kept in some distributed storage, such as Hazelcast or database. The session identifier can be in form of signed JWT, so you can keep user info in it.

OAuth Tokens: What can I link up to a user table?

I'm developing a YouTube application that needs to have a User table with the usual data associated with it in the database. I've decided to go the OAuth route for this application and have 2 tables, one of the AccessToken and one of the RequestToken.
I'm not sure what is to be linked up to a User table of some sort, would it be the access token or the request token?
If the token expires would I just lookup which user has that token then update it?
To sign the user out do I just delete the token for the user and clear the token from the session?
EDIT: In other words, I basically want a user to not have to register to my site but to just login via OAuth and have my application create a user entry in the User table so all of my other data can be linked up to that.
There are two parts to this: login and resources.
If you only want to use YouTube for login, you don't need to store the access token at all. When the user comes back from YouTube with the access token, you make one call to get their YouTube id (not sure if YouTube supports an extension parameter with the id in the token response) and discard the access token. If you also want to make other calls to access the user's YouTube data, you need to keep the access token.
A common way to implement this is:
When the user visits your site you set a session cookie with some random string we call state.
The user clicks on 'Sign In with YouTube'
You go and get a request token from YouTube, then either store it in some local cache (can be a database, redis, memory if this is a small scale app, memcache, etc.) or encrypt it and store it in another cookie on the client. When you make the request token call, include a 'state' parameter in the callback with the value set as cookie in #1. This is a critical security defense against CSRF. Also, your redirection endpoint should use SSL.
You redirect the user to YouTube with the request token (and optionally the encrypted request token secret cookie)
The user logs into YouTube, approves the application, then gets redirected back
You check that the user coming back to the redirection endpoint matches the user you originally sent over by comparing the value of the incoming state parameter with that of the session cookie from the user.
Fetch the request token secret from local cache or by decrypting the token secret cookie used earlier (which ever method you decided to use) and request an access token
Using the access token, make a YouTube API call to get the user information
Lookup in your database to see if you already have a user with that YouTube id. If you do, this is just a login, and if not, this is a new user registration so create a new record for them in your users table.

Understanding the use of the user ID in a 3-legged OAuth session?

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.

Persist Twitter OAuth session

I have a Twitter web app that allows users to submit tweets from my site. However they have to re-login every time they submit a new tweet. Is there a way to save the OAuth session and don't prompt the login screen until users clear their browser cache?
When you get the callback from Twitter after the user has validated you, you'll receive an auth_token in the headers of the request; you're meant to cache that token, and supply it every time the user makes a request.
It sounds like you're not caching that token and supplying it when the user makes a request.
You need to store the oauth_token, you can use the same for all requests.
On the FAQ of Twitter API
How long does an access token last?
We do not currently expire access
tokens. Your access token will be
invalid if a user explicitly rejects
your application from their settings
or if a Twitter admin suspends your
application. If your application is
suspended there will be a note on your
application page saying that it has
been suspended.
you need a db tables called user and user_tokens. Inside the user you have: id, user_oauth_secret, user_oauth_token. Inside the the user_token you need this columns: id, user_id, token, created, expires. make sure this token is unique (and long) with some random hash. now you can save this token to the user's cookie and find the right oauth data later.
You need to store two tokens.
When you make the OAuth request the first time, it will show the Twitter auth screen. After auth, your OAuth callback page will get two query string parameters, "oauth_token" and "oauth_token_secret" for the user. You need to store these (probably in a database) somewhere.
Then, when you request OAuth permission again from Twitter, send the two tokens, and the user will automatically be authorized.
You shouldn't have to code this yourself. There are plenty of OAuth libraries out there.
You have to maintain a long session with the user and save the access tokens. Cookies are commonly used to recognize users.

Resources