I have an Identity Server 4.0 implementation at my workplace. On top of Implicit and Auth Code flow, we are planning to use Client Credential flow for API to API call authentication.
There are few API that need to keep a log of who called it (the name of calling API). I have done a lot of digging but could not find a convincing (and secure) way of doing this.
In my understanding, in Client Cred flow, the client is going to IDS with just client secret. And obviously, this will make it practically impossible for IDS to know who is calling it. Am I right? Is there any way of knowing the client (so that some id claims can be added to the token)?
Any suggestions welcome.
EDIT: To elaborate my question and better explain my understanding of this particular OAuth flow:
Ok, so let me be clear. Let us say API X has to call API Y.
It follows the below order:
(1) X goes to IDS with Client-Id and Client-Secret for Y.
(2) IDS validates the Client-Id and Secret and issues an access-token to X
(3) X calls Y with the given access token
In step (2) above, as per OAuth 2.0's client credential flow, there is nothing except Client-ID and Client-Secret that X is required to supply. Now, if API Z wants to talk to Y, it is going to go to IDS with the same Client-ID and the same Secret.
If IDS has no way of identifying if the authentication call is from X or Z, how can it add any additional claim in the issued token?
So the only other way for Y to know if the call is from X or Z is that X or Z telling themselves (in header or url or post data) who they are (which invalidates the entire purpose of authorizing through client-cred flow). Remember that my question doesn't talk about authentication.
There are two approaches: either use unique client credentials per instance (API X, API Z are seperate clients), or use the same clientid and / or leave it to the client to provide information.
With unique clientid's you can add information about the client as a claim in the ClientClaims table, e.g. Claim('ApiName', 'apiname').
This claim is added to the access token and is available in the receiving API.
In this scenario client credentials are used as id/password, allowing the client to 'login'.
The alternative is to use the same clientid for all API's. Now it's up to the client to provide information.
One scenario can be to issue apikey's that can be used to identify the client, e.g. a guid. You can send it along with each call.
In addition there is an alternative, add a custom endpoint. Don't use client credentials but implement your own endpoint.
With extension grants you can request the information you need and translate that to a valid access token.
Through the ExtensionGrantValidationContext object you have access to the incoming token request - both the well-known validated values, as well as any custom values (via the Raw collection)
Perhaps it's an idea to 'extend' the client credentials flow with an APIKEY.
Related
For most client applications and UI approaches JWTs seem to be a good way to carry tokens for an OAuth based approach. This allows decoupling of a User/Auth service and the services that are actually being accessed.
Given this architecture
My question is: in the case of public APIs (ie Github or Slack) where a bearer key is generated with specific roles. How is that key authorized in a microservice architecture? Do those types of keys just require that the Auth service gets queried with every request?
Could an API gateway mitigate this? I would like to understand if a solution exists where there is minimal communication between services. Thank you!
Normally, this is solved using scopes. The scopes are permissions given to a user to do certain operations,for example there will be a scope for read a repository, another for update it, another one for delete etc..
These scopes are tied to the token and normally are requested by the user himself or added automatically depending on the user type. And the same as the authentication process, they could be included in the token itself coded as a claim in a jwt or they could be requested or checked by calling an oauth server when one operation is requested.
The advantages of include them in jwt is that there is not need to call an external server every time an operation is requested so there is a lower latency and less bandwith is required, also you remove a point of failure. Obviously if this solution is used the token must be properly signed or even encrypted to avoid possible manipulations.
However it has also drawbacks, and the most dangerous one is that the token cannot be revoked because this information cannot be included in the token and the service that check if the token is valid only can access the data contained in the token itself. Because of this, this kind of tokens are normally issued with a little expiry time so in case of the token is stolen, the validity of it will be very limited
Let's say that users X and Y authenticate themselves (separately) on a service's REST API, and that JSON web tokens are used for authorization between the client and server. We want to send user-specific data to each user.
Should we ask the user to specify who they are, or should the server detect it based on the authentication method (in this case the payload on the JWT)?
In other words -
Should the API have endpoints that look like this:
GET /:user/resource (for example) /user_x/resource used by user X and /user_y/resource used by Y,
or would it be better to have
GET /resource and then, in the route handler, check the user id (as part of the JWT payload) return data based on the user id?
I'm not sure which of these (if either) is the best approach, or if there might be another way to do it, such as using query strings. It would be great to hear any opinions about this.
Thanks.
The server can identify the user based on either a session cookie, or an access-token. In your case, if you use a JWT, the user-information is usually already included in the token.
So the server should just fetch the information out of this token.
Just make sure, that you check the tokens signature on the backend.
Otherwise, an attacker could just modify the JWT and send a different user-id to the server.
I'm trying to follow OpenID Connect best practices. For the simple scenario of calling API from application the OpenID Connect suggest to pass the Access Token (which is not included user identity), and if the API in some points need the user identity it should call /userinfo endpoint of OpenID Connect provider.
So the question is: Is it the best way to get the user identity in API?
Assume I have an end point named CreateOrderForCurrentUser() so each time any user call this api I need to call the /userinfo endpoint, it seems too much cost for calling an api.
Why I don't pass the Identity token to the API?
Or Why I don't put some identity claims in Access token?
Should I use HOK Token instead of Access token?
Any idea please.
It seems here is kind of same as my question: Clarification on id_token vs access_token
And he respond in comments: https://community.auth0.com/t/clarification-on-token-usage/8447#post_2
Which as my understanding means: put some identity claims in Access token (Custom Claims) and rely on that in the API.
But still it doesn't make sense. The OIDC insist to not use Access token as Identity and now we are going to add identity claims inside Access Token. Could any one clarify that?
ID_Token is used for your client app tells the app who you are , the audience of the ID Token is the id of your client app , with access token , API/resource knows whether authorized to access the API and perform specific actions specified by the scope that has been granted.
By default , it will include user identifier in access token(sub claim) , so you should know which user when calling CreateOrderForCurrentUser function . You could customize the access token to include more user related claims if needed . But i would suggest to simplify the access token , and you could use access token to acquire user information by invoking user's API endpoint .
I asked the same question in Auth0 Community and there is a discussion about it that might be helpful for others who have the same issue.
I copy the same answers here:
markd:
You are correct that you should not use an access token as proof of identity, but before you get to your API you should have already authenticated the user and received an id_token for them. If you have already authenticated the user via OIDC, as far as I know there’s nothing wrong with adding custom claims to the access token to pass data to your API. Your API could also use the client credentials grant type to pull data from Auth0.
Me:
I’m looking for the best practices. I want to be sure adding identity claims to the access token and rely on that in API does not broke any thing and is based on best practices or maybe the best practice is always call the /userinfo endpoint in API and don’t rely on Access token identity claims.
The API doesn’t know about the authentication process and don’t care about that. Any one any how pass the signed Access token to the API, it would be accepted. Now in API point of view is that proper way to rely on identity claims in Access Token? I have doubts. But I would be happy if we could ignore calling the /userinfo end point each time.
jmangelo:
I can share some (hopefully) informed views on this subject, but please do take them with a grain a salt and question stuff you disagree with or you don’t consider clear enough. When it comes with software the devil is on the details and in the security landscape it’s even more true so you need to consider best practices as what will likely be recommended for the majority of the scenarios and also what will likely be less risky; it does not mean that nothing else is possible.
For example, although the recommendation is indeed to use access tokens in requests to API’s this does not mean that there isn’t a specific scenario where technically it would also be okay to send an ID token instead.
Focusing on your particular questions and starting with the last one (3); we should not compare HOK and access tokens because they are not at the same level. In other words, you could question if in your scenario you should use bearer tokens or HOK tokens as this way and using the terminology of your linked page you would be choosing between two token profiles where each give you different characteristics.
At this time, the access tokens issued by the Auth0 service as part of API authorization are bearer access tokens so this question has only one answer if using the Auth0 service.
Jumping to the first question; it’s not that you cannot pass the ID token to the API, it’s just that the scenarios where that would be adequate are much more constrained. For example, an ID token is issued with the client identifier as the audience; it’s common to have multiple client applications so you have just coupled your API to how many client applications you have, because assuming you will validate the audience of the ID token, your API would now need to know the identifiers of every client.
For question (2) which I assume is also interested in why call /userinfo if you can include claims in the access token. I believe this can depend a lot on requirements and/or personal preferences. At this time the only format supported when issuing an access token to a custom API is the JWT format.
The above means that you have a self-contained token that once issued the API can mostly validate independently which is great in terms of scalability because the API does not need to make (frequent) external calls for validation purposes.
However, being self-contained this immediately means that any data you include directly in the token will be considered the truth for the lifetime of the token itself. If instead the API is calling /userinfo or even the Management API directly then you ensure fresh data at the cost of network overhead.
In conclusion, in my personal view the choice between network calls and embedded claims is more tied to the characteristics of the data you are interested in that just from a best practices point of view.
As a final note, even without any addition of custom claims an access token issued by the service in association to a custom API already conveys user identity. In particular, given the access token is a JWT, the sub claim will contain an identifier that uniquely identifies the end-user that authorized the current application to call the API on their behalf.
I try to implement Oauth2/OpenId Connect into microservices architecture based on Java/Spring Cloud. My current problem is about tokens propagation between microservices or through a message broker like RabbitMQ.
Very few topics talk about this. I only found this Stackoverflow thread but I don't like proposed answers.
Here are the different cases :
My microservice A receives a request initiated by the end user going through the API gateway and carrying a valid access token (JWT with scopes/claims corresponding to the final user : username, id, email, permissions, etc.). There's no problem with this case. The microservice has all informations to process the request.
1st problem : What happens if microservice A needs to call microservice B ?
1st solution : microservice A sends the access token to the microservice B
==> What happens if the token expires before arriving at microservice B ?
2nd solution : use "client credentials grant" proposed by OAuth (aka service account). It means microservice A request a new access token with its own credentials and use it to call microservice B.
==> With this solution, all data related to the user (username, id, permissions, etc.) are lost.
For example, the called method in microservice B needs the user id to work. The user id value can be set as query string.
If the method is called with the user access token, the microservice B can validate that the user id value in query string is equal to the user id value in the JWT token.
If the method is called with the service access token, the microservice B can't validate the query string value and needs to trust the microservice A.
For this cas, I heard about the "token-exchange" draft from OAuth 2. The idea is very interesting. It allows microservice A to convert the user access token into another access token with less permissions but forged for microservice A. Unfortunately, this mecanism is still in draft and not implemented in a lot of products.
2nd problem : What happens if microservice A pushs a message to RabbitMQ and microservice B receives this message ?
1st solution : Authentication and authorization are managed by RabbitMQ (vhost, account, etc.)
==> Once again, all user related data are lost. Moreover, we have 2 repositories to manage authentication and authorization
2nd solution : Like the first problem, use "client credentials grant"
What do you think about it ? Is there another better solution ?
Thanks in advance.
It's quite straightforward. There are always two use cases that we will refer to as end-user and app2app. Always gotta handle both.
Consider a simplified architecture:
Internet
User ----------------> Service A +-------> Service B
HTTP request |
+-------> Service C
Assume the user is authenticated by a token. JWT or anything else, doesn't matter.
The service A verifies the user token and performs the action. It has to call service B and C so it makes the appropriate requests and has to include the user token in these requests.
There can be a bit of transformations to do. Maybe A reads the user token from a cookie but B reads the token from the Authorization: Bearer xxx header (a common way in HTTP API to accept a JWT token). Maybe C is not HTTP-based but GRPC (or whatever developers use nowadays?), so the token has to be forwarded over that protocol, no idea what's the general practice there to pass extra information.
It's fairly straightforward and it works really well for all services dealing with end-users, as long as the protocol can multiplex messages/requests with their context. HTTP is an ideal example because each request is fully independent, a web server can process various stuff per path and argument and cookie and more.
It's also an extremely secure model because actions have to be initiated by the user. Wants to delete a user account? The request can be fully restricted to the user, there can't just be an employee/intern/hacker calling https://internal.corp/users/delete/user123456 or https://internal.corp/transactions/views/user123456. Actually, customer support for example may need to access these information so there has to be some limited access besides being the user.
Consider a real-word architecture:
Internet
User ----------------> Service A +-------> Service B --------> SQL Database
HTTP request |
+-------> Service C --------> Kafka Queue
|
|
Service X <--------------+
Service Y <--------------+
Service Z <--------------+
Passing JWT user tokens doesn't work with middleware that do not work on a end-user basis. Notably databases and queues.
A database does not handle access based on end-user (same issue with the queue). It usually requires either a dedicated username/password or a SSL certificate for access, neither of which have any meaning outside of that database instance. The access is full read/write or read-only per table with no possibility of fine permission (there is a concept of row-level permission but let's ignore it).
So service B and service C need to get functional accounts with write permission respectively to the SQL database and the Kafka Queue.
Services X,Y,Z need to read from the queue, they also each need a dedicated read-only access. They don't strictly need to have a JWT user token per message, they could trust that what's in the queue is intended, because whatever wrote to the queue in the first place must have had explicit permission to write to the queue.
It gets a bit tricky if service X needs to call yet another HTTP service that requires a user token. That's hard to do if the token wasn't forwarded. It would be possible to store the token in the queue along the message, but it's really ill advised. One does not want to save and persist tokens everywhere (the kafka queue writes messages and would basically become a highly-sensitive token database, erf). That's where the forwarding of user tokens shows its limits, at the boundaries of systems speaking different protocols with different access control models. One has to think carefully of how to architecture systems together to minimize this hassle. Use dedicated service accounts to interface specific systems that don't understand end-user tokens or don't have end-user tokens.
I just implemented Json Web Tokens to my api, but I don't understand how to verify if the user that created the token, is the one that is making the request.
For example, I have the /user/login end point, and I received the user and password for login. Then I create a json web token with the user data inside, and return it. And here is my problem, how do I know that the user that create that token, is the one that is making the request ?.
I found several ways to verify this, for example saving the user-agent + ip of the user and only accept request for that token if the user-agent + ip is xxx, but I am not really sure that is the best way.
I hope you can help me with some tips,
Thanks for all
how do I know that the user that create that token, is the one that is making the request ?.
Because the JWT includes the user ID and is signed, therefore any alterations to the content will be detected. Possession of the token is proof of authenticity
The process of issuing and authenticating with JWT is more or less like this
Issuing new JWT
User performs and authentication using its credentials
The server validate credentials, generate the JWT payload including the user data and some fields such as expiration time or issuer, and signs the token with server private key
The client receives the token and store it (in a secure storage).
Authentication
User sends a request to server. The request includes the JWT, usually in headers or as url param
The server validates the signature with the key, and extracts the user ID to know the requestor. If the signature is not valid rejects the request
Any reason you can't use a standard like OAUTH2 and let the big boys handle security for you? Rolling your own security is usually very difficult to get correct and almost all the major players provide free OATH support.
That said, I'd be hesitant to lead you down a bad path, however I've been in your shoes before so if you must roll your own security, make certain you fully read all of what OWASP has to offer. They offer very detailed threat analysis and also give suggestions that will be invaluable along your journey.
OWASP Threat Analysis
EDIT 1
A good light weight and easy to implement standard is OpenID which as their banner explains is,
A Simple Identity layer on top of OAuth 2.0
See here for a very detailed explanation of how it works:
OpenID-Wiki