OAuth 2 access token, pass by query or session - http

I searched through similar questions but none seem to answer this particular concern:
Assuming I am building a simple oauth user login system, when the oauth flow is done, should I pass the obtained access token through GET query, such as /login/provider?access_token=xxxx (assuming HTTPS), or should I store it in the session and delete it when my REST api call are done (assuming HTTPS + Signed cookies)
From what I can see: session approach doesn't expose token to even the user himself, and prevent logfile from recording ?access_token=xxxx, appear to be the safer bet.
Are there reasons for choosing GET query? Does my argument apply to OAuth 1 token and secret as well?

Related

AWS Cognito expired access token

In my application I have used aws cognito with next auth for user auth.
In the jwt callback that I have from api next-auth I receive an access token, which is then saved and sent to the client side. There, I save it in local storage and, among other things, I send it to my api which checks if it is correct.
The problem is that after an hour the access token expires and does not get a new one (always next-auth gives me old value). Has anyone had a similar flow and knows how to manage a session refresh? I will add that I am not automatically logged out because next-auth is managing it underneath, but it does not return the value of the new access token to me.
Do you have any ways how to manage this?
I can suggest a workaround that would take the least effort to solve this quickly. Amazon Cognito contains 3 kinds of tokens, the ID Token, Access Token and Refresh Token.
From the Amazon Cognito console, you can increase the validity of the token you're dealing with from there. A good idea is to refer to this answer.
Albeit you might need a couple of methods to assert security and robustness.

Google OAuth Always Showing Consent Screen

I'm building an installed application that will have features requiring the Google Drive REST API using Qt and C++. I understand Qt is now releasing new libraries to support OAuth flows but let's assume I'm a student and learning to use OAuth at this layer is a requirement for this project.
In my application, I have a working OAuth flow for installed applications that ends with an Access Token and Refresh Token being stored using QSettings (I'm open to input on whether this is a disastrously bad idea too). The application requires no authentication/login for its own sake/data, but it does need authentication to Google for calling API's using an Access Token. This application has no associated web backend being hosted; its simple and should be deployable completely locally (I've written and included a simple TCP server that will receive the authorization redirect_uri and will run and close when called from within the application).
As such, I'm curious about the best way to make sure that, when a user opens my application and wants to use the Google Drive features, they are appropriately authenticated on Google's end. Say, if I maintain an access token in the registry, and this access token is granted per-user/per-application basis (right?), then how can I make sure only the user the token belongs to is able to make calls to the API with it?
Here's my understanding and approach; feel free to correct me or educate me if I've got the wrong interpretation.
If an Access Token is found, perform the following:
Open a browser page to a Google login domain and have the user authenticate there (this could prohibit a user from being able to use a cached login session that would have access to a token they otherwise shouldn't have access to)
If user has correctly authenticated with a Google account, return control to the application and make a test call to an API using the stored token.
If the call fails (responds with an invalid_credentials) I should be able to be sure its because the access token has expired and the application will go through the flow to renew an Access Token from a Refresh Token.
If no Access Token is initially found:
Start a normal OAuth installed application flow
Get the tokens and store them so that when the user opens the application next time the former procedure is used
My issue then is the first two steps if the Access Token is found. Nominally this could be done by the typical OAuth flow but it appears that when using a localhost as the redirect uri, Google will always prompt for consent, regardless of settings for prompt and access_type authorization query parameters.
What can be done to accomplish these first two steps in a way that my application can control (i.e. not a solution that relies on a backend server being hosted somewhere)?
If this question is too open-ended for SO requirements I can make some more restrictions/assumptions to limit the problem domain but I'd rather not do that yet in case I unknowingly rope off a good viable solution.
Thanks for reading! Sorry if its a verbose; I wanted to ensure my problem domain was fully fleshed out!
If you are using an installed application, I wouldn't recommend using or storing refresh tokens. Storing refresh tokens on the client side means that if an intruder gains access to the client's application, they have infinite access to the user's application without ever having to enter the user's credentials. If you do insist on having a refresh token, ensure you follow the Google's installed app flow, with the code_verifier parameter included in your requests.
If the access token is found, you should try to verify it, and if verified then use it at the google api, otherwise force the user to login again (or refresh it if you chose to still use refresh tokens).
If no access token is found, your flow sounds fine.
A few notes on loggin in with Google:
Google will only return a refresh token if you specify access_type=offline in your auth request.
Google will only return a refresh token on the user's first authorization request, unless you always specify prompt=consent in your query params.
In my experience, when leaving out the prompt query param, the user is not prompted for their consent again. If they are logged in to google, you will get a new access token, but no refresh token, unless you have prompt=consent.
I think the idea is you use prompt=consent if you have no record of the user ever using your application. Otherwise if they have used it before, you may prefer to use prompt=select_account to allow the user to select which account he wants to use in case he has more then one, or you can just use prompt=none.
This is just my understanding of it all.
My approach I ended up using was just to deploy with an SQLite db that will be stored in the AppData roaming directory. The db schema includes a field for the user's Name (from the OpenID IDToken field if it exists), the user's picture URL (again from IDToken if it exists), the refresh and access token strings (will be stored as encrypted strings when I get around to it), the user's UID/sub string, and a field for a user name and password.
These latter two fields are authentication fields for within my own application, which, again, I wanted to avoid but it seems impossible to do so. So the user will be prompted to enter a username and password into a form, and these credentials will be checked against the existing SQLite db file mentioned previously.
If they exist and are correct, the user gets logged in and will have access to their respective access and refresh token.
If the user has forgotten their password, they'll be asked for reconsent (going through the installed app flow again), and whatever password they provided during initial login will be used as the reset password. It is considered, for my purposes, that logging into Google for the installed app flow is proof enough that the user account belongs to them and they should have authorization to reset the password.
If the user is a new user and doesn't have a record in the local SQLite db file, then they can also click a button to "Create New Account" - which effectively goes through the authorization flow as well but this time a whole new record is posted to the SQLite db with the appropriate fields filled.
There's still more optimization that could be done but at least I am getting closer to the level of security and control of access to Google user accounts that I want.
I'm not marking this as an answer because I feel like this solution is still not desired and that there should be an easier way. So if someone has evidence or experience of providing an equivalent level of authentication control without needing to maintain a local user account database then I would be more than happy to mark such a method as the solution!
Thanks again!

OAuth 2 Authorization Code - how long is it valid?

In Webserver Grant Flow
After I obtain the Authorization Code from the authorization authority (after the user has authorized my access) how long is that code usually valid form?
The reason i am asking is, can my webserver store that code and use it in later sessions to retrieve a new access token without the need for the user to re-authenticate again? Should that be the flow?
FYI my goal is make requests from Adobe Analytics and Google Analytics on behalf of my customer. So i would want to ask my customer for authorization once until he revokes my access.
Speaking strictly of Google Oauth. There are three types of codes or tokens you should be aware of.
Authorization code
Access token
Refresh token
Authorization code is return when the user clicks accept to your application accessing their data. This code is used to exchange for an access token and a refresh token. This code can only be used once and is extremely short lived 10 minutes I believe.
Access tokens are used to access private user data. They are valid for approximately one hour.
Refresh tokens are used to gain a new access token when the access token has expired. For the most part refresh tokens do not expire however if it has not been used for six months it will no longer be valid and of course the user can always remove your access.
Answer: No storing the authentication code would be pointless. You will need to store the refresh token. make sure you are requesting offline access of your users.
I cant help you with adobe analytics however I suspect it is similar this is standard Oauth protocol we are talking about.

Track OAuth 2 provider on client page

I have the ability to login via Facebook and Google on my website. This is done using OAuth2.
I use the same redirect URL whether the user is returning from facebook or google, and pass through the provider name in the state field. Is this the recommended way to track the provider? Otherwise I do not know who to validate the token with if I do not know which provider the token comes from.
Are there other preferred methods for accomplishing this?
The state parameter should be an opaque value that cannot be guessed by an attacker since it is not protected from modifications. If you need to track state, you should refer to it by using the state parameter but that parameter itself should be randomized and/or encrypted. Storing the provider identifier in plaintext in the state parameter is not safe. Users could modify the state parameter themselves or attackers could craft an authorization request with a state value that they choose.
The way to track the provider is by storing it in the backend session state and generate a reference to that session/state that you pass in the state parameter. To prevent cross-site request forgery you should also keep some encrypted/randomized cookie that binds the state to the browser. This is described in more detail: https://www.rfc-editor.org/rfc/rfc6749#section-10.12
Addendum:
One of the problems with using OAuth 2.0 + provider specific extensions for login is exactly this: you cannot establish the provider and user identity in a way that works for all providers in a uniform and generic way. In your case you'll already have to know the provider before you can perform a sensible interaction with it. Enter OpenID Connect: it is a extension profile of OAuth 2.0 that gives you login semantics in a standardized way. It would give you a verifiable JSON object (JWT) with standardized values that tell you who the provider is (iss) and who the user is (sub).
Google signin already has migrated already to OpenID Connect, as has Microsoft and others like Salesforce, hopefully Facebook will follow.

OAuth access token and refresh token creation

I'm implementing my own OAuth authentication system (with refresh_token support) for an app and I have some questions about how to do it:
Client identification: The client is registered in the auth server and gets a client_id and a client_secret. How do I generate it? is there some kind of relation between both values?.
User authentication: The client sends the users_credentials (username+password for example) + client_id and gets a refresh_token and (temp?)access_token. That access_token is the one I should use in further request or I should use a accesss_token`=F(refresh_token,access_token,client_secret). In the second case what does the F function consist on?
Access token refresh: The client send client_id, refresh_token and gets a access_token (and a optional new refresh_token). Does the access_token need the same conversion (whatever it be), as in the point 2?
If I'm wrong, when and how is the client_secret used?
Complete answers and concrete examples will be "bountied".
The authorisation/authentication server generates these values when you create an account with them (for instance when you create a developer account with Facebook or Google). If you are doing these parts yourself, they should be cryptographically secure pseudo-random numbers or letters. Remember that the client ID is usually publically visible, so choose a reasonably large set of alpha-numerics (I use 30 characters). The secret is private and can be harder to guess so I chose 30 digits with letters, numbers and symbols. These are not related to each other, it is just that one is public and the other isn't.
The usual way this works is that there is a browser redirect to the auth server passing the client id in the URL (and redirect uri) and specifically NOT the user id and password. The whole point of OAuth2 is that the client system never sees the user name and password, only the auth server. After this redirect, the auth server verifies the client id, checks the username/password (for instance) and then returns to the redirect uri with a temporary code. This temporary code is passed back to the Auth server in order to obtain an access token. Since this call is made as a POST from the server, it also passes the client secret to verify that it really is the correct client system and not someone who stole the client id from somewhere else. At this point, the auth server will return an access token (and optional refresh token - you do not need to use them, I don't).
If the client system wants to log the user in without them having to type in their username and password all the time, it can use a refresh token, if available, to call back onto the Auth server and if the Auth server is happy that the refresh token is still valid and any other business rules are correct, it can give you back another access token directly without the user being involved.
I recommend reading the OAuth2 spec here: OAuth2 Spec RFC6749. It can take a while but if you delete the bits you don't need and reduce the amount of data, there are plenty of useful examples in it.
FIRSTLY, The client identifier can be any string that you want, but it should be unique for each client. It can even be the client's choice if you wish.
The client secret should be a cryptographically strong random string. Here is how you could generate one in C#:
RandomNumberGenerator cryptoRandomDataGenerator = new RNGCryptoServiceProvider();
byte[] buffer = new byte[length];
cryptoRandomDataGenerator.GetBytes(buffer);
string uniq = Convert.ToBase64String(buffer);
return uniq;
SECONDLY, The whole point of OAuth is to allow external apps to do things on your behalf without asking for your credentials. So, you need to implement an authentication server that does the logging in part for you. The user opens the app and gets an option to Log in using your website. You tend out access tokens and refresh tokens once the user has keyed in his credentials. The app can then simply use the tokens to perform actions on the user's behalf. I wrote an answer to How would an efficient OAuth2.0 server / provider work? that explains how access tokens can be constructed.
Remember, the need for refresh tokens and the lifetime of access tokens purely depends on how you intend to use them and what does your security framework look like.
LASTLY, The refresh token can also be an HMAC encoded string/a JSON object as I had explained in the answer to the linked question. You can have random refresh tokens and a large backend storage to keep it to verify the tokens in the incoming requests, or have HMAC encoded strings for added security/less storage requirements/latency to decrypt/encrypt tokens.
Also, do make sure that you go through all the flows and possibly the RFC too as mentioned by Lukos.

Resources