OAuth - Binding local user to 3rd party - authentication

I'm working on a mobile application, in which, the user can go for Facebook, Twitter or Foursquare authorization (via OAuth) rather than creating a new account and password.
The problem is, I'm not sure what should I store in my DB to point a 3rd party account. The auth_token, acquired from OAuth process seems to expire or change in some situations (like when the user changes password). So, it's not a good option.
What would be the long term option? I mean, even if user unauthorized my app, then authorizes it back, I would like to be able to find out the local user corresponding to them. Should I use the respective API's of each website and dig out user_id and store it? That would be consistent in between sessions I believe.
Any suggestions?
Thanks.

When you are getting the authorization from the sites, you need to only store the access_token (and refresh token if OAuth 2.0). With a OAuth 2.0 access_token, it will expire occasionally and you will need to use the refresh_token to get a new access_token. The user changing the password will not change the token, but the user would have the ability to revoke the token at any time.
Since they have to go through your mobile app to get the OAuth authentication, you should be able to link them together easily.

Related

Who generates JWT when using Google OpenID Connect authnentication for my ASP.NET Core Web API app?

I am building an ASP.NET Core 6 Web API application for mobile clients (and maybe later SPA JS app). The application should have sign-in with Google option. I also want to add my own app's custom sign up and sign in options that would also be based on JWT authentication and not cookie.
I understand that for my custom sign in flow my app will generated JWT that will be sent to the client.
But I have few questions how that works when user signs-in with its Google account:
who's responsibility is to generate the JWT when user signs-in with its Google account? Is that responsibility of Google or mine application? I don't want Google to return JWT to the client in the cookie.
Then when client is authenticated with Google, and sends requests to my application, how can my application validate JWT token it gets?
When user signs in with Google for the first time, should I automatically register that user in my application (I am using Identity framework) by taking claim values (email) from the JWT? What is the general practice here?
I am trying to understand these processes and flows so sample code is not necessary (but I do welcome it).
Ad.1. Normally, in a larger system, you would have an authorization server (AS) that would handle user authentication and the issuance of tokens. Your clients would contact only the AS, and the AS will be able to provide the user with different forms of authentication: e.g., through your website's password or through Google. The AS is the single point of issuing tokens to your clients. It can issue tokens regardless of the authentication method used. So it then doesn't matter whether the user authenticated with Google or a password, the client will still get the same access token.
Ad.2. When the AS issues token to your client, then you don't have any problems validating that token. The client doesn't care if the user authenticated with Google or not, it's not relevant in this case.
If you decide to skip using an AS and let the client receive tokens directly from Google, then you can still verify them. An ID token is a JWT and can be easily validated with a JWT library using verification keys provided by Google. Access tokens returned by Google are opaque tokens (If I remember correctly), and you need to check whether Google exposes an endpoint to verify them.
Ad.3. That is the general practice. When the user authenticates with Google and you notice that you don't have that user's data in your system, then you take the information from Google's ID token and create a user entry in your system.

How to use Google Identity to log in from multiple devices?

How can I use Google Identity platform as a login / registration system for my own service?
Specifically - how can I do this and support login for same user from different devices?
Using for web service, nodejs without npm modules: passportjs / googleapis / google-auth-library.
My idea:
User opens myClientApp/login page and clicks on GoogleLogIn button which will ask him to authorize my service for specific scopes of his Google account.
I then get the refresh token & access token and save it in DB, then send the refresh token to the client with cookie.
Whenever I make a call to my own service API I send the refresh token from the cookie.
As long as I have valid access token saved in my DB or the refresh token is not expired - I treat the user matching that refresh token as an active session for my service.
Security problems:
cookies attacks, and the refresh token is easily accessed from the browser. Could use https / encryption and more methods to secure the cookie and it's value. Still- someone could copy the cookie from one computer to another!
Multiple login problems:
If the user login on different device, a new refresh token will be created. The previous device the user logged in to will now hold a wrong refresh token in the cookie...
Could the OpenID solve this? Do I need to use JWT?
What is the most secure way to use Google Identity login in my own service while supporting multiple devices login for the same user?
First, make sure that you really understand the security implications for what you want to do.
For example, NEVER send the Refresh Token to a client.
If you want to use the same tokens for the same client on multiple devices, you have a chicken and egg situation. How do you "authenticate" the user at each device. How do you know that user "John" is actually user "John" but on a different device the first time?
Your goal is not to trade convenience for less security. Your goal should always be security first, no matter the inconvenience.
A better approach is to let Google authenticate and authorize a user on each device. They only have to do this once per device. Your backend systems keep track of the Refresh Token issued for each device. You can then generate the Access Tokens and Identity Tokens when needed - they expire after one hour anyways. Store a cookie on the user's device that identifies them to your system so that you can look up who they are, get the Refresh Token, create new Access Tokens, etc.
There is a limit to the number of Refresh Tokens that can be issued before the oldest ones are voided. I think the number is 50. This is usually not a problem. If a Refresh Token is invalid, just put the user back thru the authenticate process and store the new token.
Also provide the user with a sign-out method that removes all stored tokens in your system.
The cookie that you store on the client's devices should be opaque meaning that there is no stored information in the cookie and the cookie is only valid for that device and no other devices. This solves the stolen cookie moved to another device problem.
I will now touch on some of your questions:
My idea: User opens myClientApp/login page and clicks on GoogleLogIn
button which will ask him to authorize my service for specific scopes
of his Google account.
Google OAuth does not work that way. You send the user to a URL, Google manages all display and input with the end user. Once everything is complete a callback URL on your server is called and you are passed a code. The exact details depend on the type of OAuth Flow that you are using.
I then get the refresh token & access token and save it in DB, then
send the refresh token to the client with cookie.
During the OAuth Flow you will request the Access Token, Refresh Token and Identity Token. The Refresh Token is saved in the database. Never send this token to the client. Read my suggestion above about creating an opaque cookie that you send to the client.
Security problems: cookies attacks, and the refresh token is easily
accessed from the browser. Could use https / encryption and more
methods to secure the cookie and it's value. Still- someone could copy
the cookie from one computer to another!
Create an opaque cookie that is only valid for that device and no other devices. If a client sends you a cookie intended for a different device, consider this a problem and invalidate all cookies, tokens, etc for this user on all devices.
Multiple login problems: If the user login on different device, a new
refresh token will be created. The previous device the user logged in
to will now hold a wrong refresh token in the cookie...
I covered this issue above. Store the Refresh Token generated for each device in your DB. Consider each device / Refresh Token / cookie as a set.
Could the OpenID solve this? Do I need to use JWT? What is the most
secure way to use Google Identity login in my own service while
supporting multiple devices login for the same user?
By Open ID I think you mean Open ID Connect (OIDC). This is already integrated into Google OAuth and this is the part that generates the Identity Token.
Do I need to use JWT?
Google OAuth Tokens are generated from Signed JWTs. However for the most part you do not need to worry about the format of tokens. Google provides endpoints that validate and decode Google OAuth tokens.
What is the most secure way to use Google Identity login in my own
service while supporting multiple devices login for the same user?
I covered this question in the first part of my answer above.

What is the correct way to use OAuth for mobile and website consuming my own API?

I have a question more related to the way OAuth 2 is working but since using IdentityServer to implement OAuth I think it's relevant. I could not find an answer anywhere.
I'm building a website and a mobile app that consumes my own API. Each user of my app will have a username and password, that will give him access to the app/website and though the API to his information.
I'm not sure about the right way to handle the flow for user login:
On the website I have my own designed login form. I don't want to move the user to my auth server to login, and then have him approve the information he gives - he is the user on my system - I have access to all information - kida like facebook has a login and access to the informatio - they don't ask what you're willing to give them. So is implicit really the way for this?
On the mobile app I also have a login form and now I read here (https://datatracker.ietf.org/doc/html/draft-ietf-oauth-native-apps-10) that the OAuth approach is to have the login in a WebView?? Doesn't look like facebook login is in a WebView on their mobile app.
The approach I was first lookin at is the Resource Owner. Users will login, get the token and the refresh token and can start working against my APIs. But storing my client_id and secret on the mobile app? on the website javascript files? doesn't feel right. I can of course make a call to an API that will mask those and be a proxy to the login process... but... (read #4).
In the future I would like to allow access for third-party developers. For them to allow login for users of my system I will use the implicit flow. Also, I plan for those developer accounts to have restricted API access (for example, the number of calls to the API will be limited by plan). What prevents those developers from asking for the username and password of their account on my system on their website, getting the response from my servers with the access token and refresh token, and using my API however they want, without restrictions, and having access to the entire user profile?
Lets say I'm sticking to the resource owner flow, receiving back from the server a token and a refresh token. What should I store on the mobile device and how? What should be stored in the browser and how? the refresh token? and each time he opens the app get a new updated token with that refresh token?
Edit
Just to clarify, because I find a lot of lectures and articles that explain the process from an API consumer point of view (ie. the third-party developer): I am the API owner and the auth server owner, I'm the owner of the user accounts (they are my users of my services), I'm also my own consumer (though the website and the mobile app), and in the future I want to enable third-party developers to allow my users to login with their accounts of my service (kinda like Facebook or Google)
You're correct that you shouldn't store the client_secret in your app, but I doubt you will get around storing the client_id. You could disable the consent screen for your app as well, and build a native login view. You need to store the access_token and the refresh_token on the device (maybe encrypted in a database) if you don't want the user to login everytime they use your app.
As for problem 4, you could do the following:
Embed the client_secret in your (web) app
Set up which hosts have access to your api on the IdentityServer
The IdentityServer generates a salt and sends it to the client
The client calculates a session_secret using hash(ip_address + session_salt)
The client uses the session_secret and the client_secret for the API call
Server validates the hash and client_secret
It's nearly impossible to completely prevent someone from using your API. But you should add various rate limiting methods, such as limiting IP addresses, API calls etc. But nothing will stop someone decompiling your app and accessing your client_id.

Is there any API to get Dropbox token using username and password?

I am trying to get an access token using my dropbox username and password.
I don't want to go and generate it from there site, as mentioned in there help documents.
No, Dropbox API apps should use the OAuth app authorization flow to get an access token for the user, so that the app doesn't have to directly handle the user's credentials. You can find more information on this process here:
https://www.dropbox.com/developers/reference/oauthguide
The method of generating it on the App Console that you mentioned only works for the owner of the app, but the OAuth app authorization flow can be used for any account.
Note that while this does require manual user intervention, it generally only needs to be done once per user. Once the app has an access token for a user, it can store and re-use the token for future API calls without further manual user intervention.
Dropbox API access tokens don't expire by themselves, though they can be manually revoked by the user.

Assessing login state for each request when authenticated using OpenID, OAuth and/or OAuth 2.0

I'm in the process of building an expanded login/signup area for my website which includes OpenID, OAuth (Twitter) and OAuth 2.0 (Facebook) sign in options.
Once a user has authenticated successfully and I've stored their access tokens in my database and written a cookie linking the user to their login state, what best practice should I be using to determine that the user's access token is still valid? It seems that having to call the authentication provider for every single request to my site would slow things down for the user and I can't imagine that is what other sites are doing.
My guess is that I should store a cookie which is valid only for the current browser session and thus that cookie will expire when the user closes the browser, forcing a new access token to be generated on the next request (and a new cookie to match). I would also expire the cookie early if the user explicitly logs out.
The only question I have of course is if, for example, the user has my site open in a tab, then they open their authentication provider in another tab and sign out of that site, but continue to browse my site, they won't be logged out of my site, even though technically they're supposed to be able to log out using the third party provider.
Is this one of those "it doesn't really matter" scenarios, or am I approaching the whole thing the wrong way?
Definitely the service providers do not want you pinging their service for every request that comes into your service. Even Google balks at the thought of that. You could set up some kind of a timeout to check every 5 minutes, but I think your idea of a session cookie is the ideal one. But yes, it depends on what you're trying to achieve.
If you are just using these services to log the user in and that's it, then throw away the access token you have as soon as you verify the user is logged in and set your own session or persistent cookie. You don't need their access token any more.
If you do want to access the user's data on these services, then of course keep the access token around. But you still probably should maintain your own concept of whether the user is logged in. If I recall correctly these access tokens are typically long-lived (in OAuth 1.0a anyway) and they won't help you when the user returns to determine whether the user is who they say they are unless either you have your own cookie or you send them through the login service again.
If you are just using OAuth / OpenId for login purposes, I don't think you should worry about any of it.
What you should worry about is if your users are who they say they are as their (OAuth/OpenId provider) users.
If your website intends to interact with Twitter and Facebook, that's a different matter, but still it pretty much solves itself. When you try to interact with FB, while your user has logged out of there, FB will prompt your user to login again.
Bottom line, I think it's really a non-issue.