In my application, I have separate microservices for user authentication and user profile information. The user authentication service is using Spring Security OAuth2/JWT. Once a user successfully logs in, a JWT token is issued with the user unique identifier.
My query is how other services should retrieve user profile information. Should I put this information (such as first name, last name etc) into the JWT token or should I create an API on the user profile service which retrieves the user profile information once the token is retrieved?
Any best practice advice would be appreciated.
So far most approaches i've seen was to store only user's login in JWT token and have another service which gives you other needed informations by login, and this seems like the best approach to me (in case of any security leak's login is the only thing that can be stolen, and not user's first or last name).
I think it is important to highlight that OAuth2 is intended to be an authorization protocol rather than authentication.
OpenID Connect solves this problem by separating the identity (ID_Token) and the authorization (access token) into two different tokens for the application to consume. Rather than implementing your own, may I suggest that you consider OpenID Connect?
I have had similar discussions with my team while working on the authentication microservice. Though it's important to understand that JWT is an encoding and not an encryption so it's always advised not to keep sensitive data in JWT. Though the items that we decide to keep in JWT should also depend on the problem statement we are solving. There can be use cases where saving the Username or email id is not a sensitive information and you may want to keep that in JWT just to avoid an extra API call.
Related
Currently I have this setup:
At login, and in every subsequent request after login, a mobile application that I have built uses Basic Authentication to authenticate the user with a web service that serves the app with information it requests.
On every request the Authorization header is inspected, the password and username are extracted from the header, the password is hashed using a proprietary DLL (so the web service doesn't actually contain the hashing algorithm) and compared to the hashed password associated with the username that is stored in the database.
I have now been asked to include Azure AD SSO in the login options.
After reading much about the topic, this looks seems to me like the setup:
I'm curious about a few things:
Is this setup correct, more or less?
Does the app send the Identity Token to the web service? If so, how does the webservice validate that token?
Is it correct that the webservice can match the Azure Identity to the DB user using one of the claims in the Security Token?
Where do Access Token fit in this picture?
Thanks for the help!
(Side Note: I know that Basic Authentication is not the preferred way to go in the first scenario. This was a temporary decision till we developed the token handling code, it only works using HTTPS and this is an internal application - you wouldn't be able to activate the app unless you have a code we give you)
I have little experience in azure ad but I think we could talk about your case.
First, whatever id token and access token are both jwt token, so to your web service application, you need to use jwt decode library to decrypt the token and get claims it contains. Here we need to know the difference between id token and access token, and I think you'll know that for your web service application, if it's more likely to play the role of an api application, you need to use access token because this token also contains user information. Then you need to add code in your program to decode the token and check if it's a 'valid' token for the request.(Because you've used azure ad to achieve the login part, you don't need to use your custom login part.)
Next, the signing in feature provided by azure ad requires to use account and password in the tenant which azure ad belongs to, the user accounts may look like xx#xx.onmicrosoft.com, it doesn't required to keep sycn with the accounts in your database, so it's difficult and needless for you to compare the user name obtained from the decoded token with those in your database. Because when your web service received the token(id or access token), that means someone has passed the authentication from azure ad. The token contains user information including role, expired time etc. You need to check if the token has expired and if has the correct scope. (Let's see a common situation, microsoft provides many graph apis to call, when accessing these api, we need to provide access token in request head with matching scope, e.g. https://graph.microsoft.com/v1.0/me
requires a delegated api permission of User.Read)
To sum up here, if your web service just required the users in your database to sign in then can be access, id token and access token are both suitable for you because they both contains user name like 'xx#xx.onmicrosoft.com', what you need to do is decode the token and check if the token has expired and whether this user exists in your database(you may set up a mapping between them).
I currently have a backend running on AWS Lambda and I'm using DynamoDB as a database. In Dynamo, there is a list of users and each user has specific permissions as to what routes they have access to through the API. There is no issue here.
I have not built the front end yet, but I will be logging in users using Google Auth, more specifically with the react-google-login component.
My question is: Once a user is logged in to the site, should I trust the JWT from Google (after verifying its legitimacy
here with the Google API) which returns the user information (Name, Email), lookup the user item inside of Dynamo to retrieve their permissions, and then serve their request?
This seems like the logical thing to do but I was looking for some confirmation. My one worry is that someone could use a supervisors name & email to authorize a request but if the lambda must accept a JWT created by Google as entry, I believe this problem is solved correct?
I have API Keys as well for every user for some external functionality, but I have that covered since it's just a Dynamo call away. My only concern is with the front end requests to Lambda since I do not want to roll my own auth/jwt.
Here is what I was envisioning.
Thank you!
Normally you should use access tokens for that purpose. The ID token should be meant only to authenticate the user, and the access token should be used to authorize access.
The best scenario would be to have a separate Authorization Server which could issue access tokens, and there are some open source solutions out there which you can use.
If you really don't want to setup your own AS then you could follow the scenario you outlined - the part with verifying JWT from Google and checking permissions in the DynamoDB is what the Authorization Server would normally do to issue an access token.
Just remember to thoroughly validate the incoming JWT - not only the signature with Google, but also check if that is a token created for your client / audience, etc. Otherwise someone could take a Google ID token JWT from their client and gain access to your API. This article lists best security practices when working with JWTs.
Also remember that ID tokens might have short expiration times and there are no means of automatically refreshing them (like you can do it with a refresh token in case of an access token), so you might end up having to reauthenticate quite often.
If I'm integrating authentication from a third party service into my app, such as github or slack for example, when a user goes to sign up on my app and successfully authenticates with the third party service, what does the data look like that I will receive?
Specifically, if this is a user's second or third time signing in, and they've already signed up before, how do I know they're already signed up? What data do I need to store in my database to know who they are?
Are there common maintenance or upkeep I need to perform on the data about a user's identity? Does it go stale?
The data you receive depends on the response_type and scope parameters of the request uri you are constructing when contacting the third party services. The id_token received is always a JSON Web Token (JWT).
When you request the "openid" scope, the id_token will have "iss", "sub" claims as part of the token payload. These two claims uniquely identify the user by who the provider is and the unique id for that user in that provider. The combination of these two values can be saved in your database to identify if the user is already signed up or not.
When you use a third party provider and save just the bare minimum information (iss, sub), then you do not have to keep up with any information. This would be a nice approach when you don't want to deal with any maintenance. If you need user profile related information you could request the "profile" scope as part of your request which will have more information about the user.
Thank you,
Soma.
I'm about to start working on application with rest API and I want to use apigility. There is one problem unfortunately with this idea. I cannot find reliable source of information how to allow for authentication by oAuth for regular users.
I need to provide access for angular app and native mobile one (possibly in future for third-party web apps). All resources that I have found are about granting access to api for specific client application, not for specific users that use this applications. I don't want to implement two different authentication methods, so if there is a way to resolve this issue with apigility it would be great.
Do you have any suggestions how to approach this? I know that I can generate client id and secret for all registered users but this seams a little crappy solution and I have database schema already in place for storing user info.
What you're likely looking for is the "password" grant type. In this scenario, you will have a way of registering users and their passwords, and then a "login" screen of sorts. This login screen will send the following information:
username
password
client_id -- this will be the OAuth2 client ID (not the user ID!) for the application
"grant_type": "password"
Note that you are NOT providing the client_secret in this scenario! In the case of a user credential scenario, the user's credentials are validated, and then the server verifies that the client_id supports this grant type.
If the user provides successful credentials, then the OAuth2 endpoint will return a token, a TTL, and a refresh_token (which, if you send it before the TTL expires, will give you a new set of tokens).
From here, you will then send the token in the Authorization header: "Authorization: Bearer ". Apigility will then pick this up on each request and validate the token.
The validation returns also the username as part of the identity. This means that you can query the ZF\Mvc\Identity to retrieve the user in order to perform user-specific ACL assertions later!
Poke me on the mailing list (http://bit.ly/apigility-users) if you need some more direction.
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.