In the OpenID Connect spec the azp (authorized party) claim seems to have a contradiction.
In the ID token definition section 2 it says:
azp
OPTIONAL. Authorized party - the party to which the ID Token was issued. If present, it MUST contain the OAuth 2.0 Client ID of this party. This Claim is only needed when the ID Token has a single audience value and that audience is different than the authorized party. It MAY be included even when the authorized party is the same as the sole audience...
But in token validation section 3.1.3.7, one of the steps seems to say the opposite:
If the ID Token contains multiple audiences, the Client SHOULD verify that an azp Claim is present.
Could anyone shed some light on this apparent discrepancy? Only the second instance uses declaratory language, so I'm leaning towards favoring that in my implementation.
You're correct, the whole azp situation in OIDC is confusing. For what's it's worth, they have an open issue associated with it; see OIDC - Issue 973 (azp claim underspecified and overreaching).
From the definition of "aud" in JWT and its use in Connect's ID Token (relevant spec text is copied below), it seems that that the client id of the client/RP that made the authentication request has to be one of the values, or the only value, of the "aud" claim in the ID Token. That's logical and consistent and provides reliable and interoperable guidance to implementers about producing and consuming the ID Token. I think that the client id of the RP/client that made the authentication request should always be represented in the aud of the returned ID Token.
The text around "azp" in the ID Token section and the ID Token Validation section seems to maybe suggest something different, however. Like perhaps that the client id of the RP/client that made the authentication request could, in some totally unspecified circumstance, be the value of the azp claim and that the aud would not identify that client as an intended recipient. Am I misinterpreting things?
Personally, from the client application developer perspective, the best course of action seems to be honoring the ID Token validation rules which always imply that the value within azp will also be present as an aud. However, according to what's available online Google seemed to use it a bit differently so you could have a value in azp not listed within aud, so there may be situations where you play by Google rules and not (just) OIDC.
If you're implementing an OP a probably good option is also to entirely stay away from including azp in your issued tokens if possible or only include it when using multiple audiences with one of them being the value also in the azp.
I think the two sections are not conflicting each other on the concept level (a bit confusing on the wording though).
if there is a single audience which is different from azp, it makes senses to have both azp and audience to show that difference. In a multiple-audience case, at least one of the audiences will be different from azp and hence azp must be present to make it clear.
azp usually equals to client id (the application requests the token). audience of the token can be the app itself or another application which receives the token for validation.
Related
I am currently developing financial services as a personal project.
In order to strengthen security in the project, it is designed and implemented to process authentication at the gateway stage using AWS API Gateway.
I tried to log in using a mobile phone number and the received authentication number, and I don't think this is appropriate for Cognito and IAM identifiers, so I'm going to run the Node Auth Server that issues and verifies JWT tokens in AWS Lambda.
In the process, I tried to include an identifier such as user_id or uuid in the payload of the JWT token, but my colleague opposed it.
His opinion was that access token should only engage in authentication and that the token should not contain a user identifier.
I agreed with him to some extent, but if so, I wondered how to deliver the user identifier in an API such as "Comment Registration API".
Should we hand over the user identifier along with the access token to the client when login is successful?
in conclusion
Is it logically incorrect to include the user identifier in Access Token's Payload?
If the answer to the above question is yes, how should I deliver the user identifier when login is successful?
I wanted to hear the majority's opinion, so I posted it.
Thank you.
Typically you want enough information in the access token so that you can also do proper authorization about what the user/caller is allowed to do.
Typically, you separate authentication and authorization like the picture below shows:
So, to make an effective API, you do want to avoid having to lookup additional information to be able to determine if you are allowed to access some piece of data or not. So, I typically include the UserID and some other claims/roles in the token, so that I can smoothly let the user in inside the API.
However, adding personal information in the access token might have some GDPR issues, but sometimes it might be necessary to also add. But I don't see any issues adding information like UserId and roles in the token.
Yes it is logically correct and a normal thing to do. To see how to do it in a Node Auth Server, you can look at this: https://auth0.com/blog/complete-guide-to-nodejs-express-user-authentication/
I've implemented Sign In with Apple in my iOS app, and now I have also implemented it in my website. What surprises me is that both flows end up with a difference audience value in the id token, is that to be expected? The iOS app uses the app's bundle id, and the web flow uses the service id's identifier.
So for example in the iOS flow the audience is com.domain.app and in the web flow the audience is com.domain.siwa. When I'm sending the id token to my server where I am doing the validation logic, I now have to know where the id token comes from so I can use the correct audience. It would be easier if the audience could just be the same for both flows. Is that possible? Or should I just forgot about this and work with two difference audience values?
The reason why the audience aud claims of your JWT tokens differ is that, as Apple themselves puts clearly, the audience registered claim identifies the recipient for which the identity token is intended.
Simply put, as the audiences are literally different, the aud claim should & will always be different.
This is not unique to Apple and is actually taken from RFC7519: JSON Web Token, so trying to make the aud claim values the same is actually going to be against the JWT spec.
Here is how RFC7519 describes it:
The "aud" (audience) claim identifies the recipients that the JWT is
intended for. Each principal intended to process the JWT MUST
identify itself with a value in the audience claim. If the principal
processing the claim does not identify itself with a value in the
"aud" claim when this claim is present, then the JWT MUST be
rejected. In the general case, the "aud" value is an array of case-
sensitive strings, each containing a StringOrURI value. In the
special case when the JWT has one audience, the "aud" value MAY be a
single case-sensitive string containing a StringOrURI value. The
interpretation of audience values is generally application specific.
Use of this claim is OPTIONAL.
If you need to, I would say to just deal with different audience values but what are you using the aud claim value for anyway?
If you're trying to restrict specific features, for example, based on a certain "audience", feel free to use it however the use of this claim for business logic isn't really that widespread.
Other claims will most likely be better suited depending on what you're exactly trying to achieve here.
ID TOKENS
The audience for an ID token represents the client application, so you will have 2 different audience values. ID tokens are typically validated by the client app, eg in the mobile code, but using an API to do the work is also possible.
ACCESS TOKENS
Here is the OAuth standard behaviour:
Don't send ID tokens as credentials in API requests - send access tokens instead. Access tokens have an audience that specifies an API or a set of related APIs, eg api.mycompany.com.
Issue your own access tokens, where you can control the scopes and claims that your APIs will need for authorization - Apple tokens are not designed to be used in your own APIs
AUTHORIZATION SERVER (AS)
The optimal way to issue your own tokens is to let an AS manage the connection to Apple for you - as in this tutorial.
SUMMARY
Hopefully this gets across key points in case useful. Aim to base solutions on the standard design patterns that have been vetted by experts for many years. Sometimes vendor specific guides don't explain these principles well.
Preface
I'm developing several web services and a handful of clients (web app, mobile, etc.) which will interface with said services over HTTP(s). My current work item is to design an authentication and authorization solution for the product. I have decided to leverage external identity providers, such as Facebook, Google, Microsoft, Twitter, and the like for authentication.
I'm trying to solve the problem of, "when a request comes to my server, how do I know who the user is and how can I be sure?". More questions below as well...
Requirements
Rely on external identities to indicate who I'm dealing with ('userId' essentially is all I care about).
The system should use token-based authentication (as opposed to cookies for example or basic auth).
I believe this is the right choice for scaling across multiple clients and servers while providing loose coupling.
Workflow
Based on my reading and understanding of token-based authentication, the following is how I imagine the workflow to be. Let's focus for now on Facebook in a web browser. My assumption is that other external identity providers should have similar capabilities, though I have not confirmed just yet.
Note, as of writing, I'm basing the following off of Facebook login version 2.2
Client: Initiates login to Facebook using the JavaScript SDK
Facebook: User authenticates and approves app permissions (to access user's public profile for example)
Facebook: Sends response to client which contains user’s access token, ID, and signed request
Client: Stores user access token in browser session (handled by SDK conveniently)
Client: Makes a request to my web service for a secure resource by sending along the user’s access token in the authorization header + the user’s ID (in custom header potentially)
Server: Reads user access token from request header and initiates verification by sending a request to the debug_token graph API provided by Facebook
Facebook: Responds back to the server with the user access token info (contains appId and userId)
Server: Completes verification of the token by comparing the appId to what is expected (known to itself) and the userId to what was sent on the client request
Server: Responds to the client with the requested resource (assuming the happy authorization path)
I’m imagining steps 5-9 would be repeated for subsequent requests to the server (while the user’s access token is valid – not expired, revoked from FB side, app permissions changed, etc.)
Here's a diagram to help go along with the steps. Please understand this system is not a single page application (SPA). The web services mentioned are API endpoints serving JSON data back to clients essentially; they are not serving HTML/JS/CSS (with the exception of the web client servers).
Questions
First and foremost, are there any glaring gaps / pit falls with the described approach based on my preface and requirements?
Is performing an outbound request to Facebook for verifying the access token (steps 6-8 above) per client request required / recommended?
I know at the very least, I must verify the access token coming from the client request. However, the recommended approach for subsequent verifications after the first is unknown to me. If there are typical patterns, I’m interested in hearing about them. I understand they may be application dependent based on my requirements; however, I just don’t know what to look for yet. I’ll put in the due diligence once I have a basic idea.
For instance, possible thoughts:
Hash the access token + userId pair after first verification is complete and store it in a distributed cache (accessible by all web servers) with expiry equal to access tokens. Upon subsequent requests from the clients, hash the access token + userId pair and check its existence in the cache. If present, then request is authorized. Otherwise, reach out to Facebook graph API to confirm the access token. I’m assuming this strategy might be feasible if I’m using HTTPS (which I will be). However, how does performance compare?
The accepted answer in this StackOverflow question recommends creating a custom access token after the first verification of the Facebook user token is complete. The custom token would then be sent to the client for subsequent requests. I’m wondering if this is more complex than the above solution, however. This would require implementing my own Identity Provider (something I want to avoid because I want to use external identity providers in the first place…). Is there any merit to this suggestion?
Is the signedRequest field present on the response in step #3 above (mentioned here), equivalent to the signed request parameter here in the ‘games canvas login’ flow?
They seem to be hinted as equivalent since the former links to the latter in the documentation. However, I’m surprised the verification strategy mentioned on the games page isn’t mentioned in the ‘manually building a login flow’ page of the web documentation.
If the answer to #3 is ‘Yes’, can the same identity confirmation strategy of decoding the signature and comparing to what is expected to be used on the server-side?
I’m wondering if this can be leveraged instead of making an outbound call to the debug_token graph API (step #6 above) to confirm the access token as recommended here:
Of course, in order to make the comparison on the server-side, the signed request portion would need to be sent along with the request to the server (step #5 above). In addition to feasibility without sacrificing security, I’m wondering how the performance would compare to making the outbound call.
While I’m at it, in what scenario / for what purpose, would you persist a user's access token to a database for example?
I don’t see a scenario where I would need to do this, however, I may be overlooking something. I’m curious was some common scenarios might be to spark some thoughts.
Thanks!
From what you describe I'd suggest to use a server-side login flow as described in
https://developers.facebook.com/docs/facebook-login/manually-build-a-login-flow/v2.2
so that the token is already on your server, and doesn't need to be passed from the client. If you're using non-encrypted connections, this could be a security risk (e.g. for man-in-the-middle attacks).
The steps would be:
(1) Logging people in
You need to specify the permission you want to gather from the users in the scope parameter. The request can be triggered just via a normal link:
GET https://www.facebook.com/dialog/oauth?
client_id={app-id}
&redirect_uri={redirect-uri}
&response_type=code
&scope={permission_list}
See
https://developers.facebook.com/docs/facebook-login/manually-build-a-login-flow/v2.2#login
(2) Confirm the identitity
GET https://graph.facebook.com/oauth/access_token?
client_id={app-id}
&redirect_uri={redirect-uri}
&client_secret={app-secret}
&code={code-parameter}
https://developers.facebook.com/docs/facebook-login/manually-build-a-login-flow/v2.2#confirm
(3) Inspect the access token
You can inspect the token as you already said in your question via
GET /debug_token?input_token={token-to-inspect}
&access_token={app-token-or-admin-token}
This should only be done server-side, because otherwise you'd make you app access token visible to end users (not a good idea!).
See
https://developers.facebook.com/docs/facebook-login/manually-build-a-login-flow/v2.2#checktoken
(4) Extending the access token
Once you got the (short-lived) token, you can do a call to extend the token as described in
https://developers.facebook.com/docs/facebook-login/access-tokens#extending
like the following:
GET /oauth/access_token?grant_type=fb_exchange_token
&client_id={app-id}
&client_secret={app-secret}
&fb_exchange_token={short-lived-token}
(5) Storing of access tokens
Concerning the storing of the tokens on the server, FB suggests to do so:
https://developers.facebook.com/docs/facebook-login/manually-build-a-login-flow/v2.2#token
(6) Handling expired access tokens
As FB doesn't notify you if a token has expired (and if you don't save the expiry date and compare this to the current timestamp before making a call), it's possible that you receive error messages from FB if the token got invalid (after max. 60 days). The error code will be 190:
{
"error": {
"message": "Error validating access token: Session has expired at unix
time SOME_TIME. The current unix time is SOME_TIME.",
"type": "OAuthException",
"code": 190
}
}
See
https://developers.facebook.com/docs/facebook-login/access-tokens#expiredtokens
If the access token becomes invalid, the solution is to have the person log in again, at which point you will be able to make API calls on their behalf once more. The login flow your app uses for new people should determine which method you need to adopt.
I dont' see any glaring gaps / pit falls, but I'm not a security expert.
Once your server has verified the given token (step 8), as you said:
The accepted answer in this StackOverflow question recommends creating a custom access token after the first verification of the Facebook user token is complete. The custom token would then be sent to the client for subsequent requests. I’m wondering if this is more complex than the above solution, however. This would require implementing my own Identity Provider (something I want to avoid because I want to use external identity providers in the first place…). Is there any merit to this suggestion?
IMHO is the way to go. I would use https://jwt.io/ which allows you to encode values (the userId for example) using a secret key.
Then your client attach this token to every request. So you can verify the request without need to a third party (you don't need database queries neither). The nice thing here is there is no need to store the token on your DB.
You can define an expiration date on the token, to force the client authenticate with the third party again when you want.
Let's say you want your server be able to do some action without the client interaction. For example: Open graph stories. In this scenario because you need to publish something in the name of the user you would need the access token stored on your DB.
(I can not help with the 3 and 4 questions, sorry).
Problem with Facebook is that they do not use OpenId connect on top of Oauth (https://blog.runscope.com/posts/understanding-oauth-2-and-openid-connect).
Thus resulting in their custom ways of providing Oauth authentification.
Oauth2 with OpenId connect identity services usually provide issuer endpoint where you can find URL (by appending ".well-known/openid-configuration") for jwk's which can be used to verify that JWT token and its contents were signed by the same identity service. (i.e access token originated from the same service that provided you jwk's)
For example some known openid connect identity providers:
https://accounts.google.com/.well-known/openid-configuration
https://login.microsoftonline.com/common/v2.0/.well-known/openid-configuration
(btw it is not a coincidence that Attlasian provides only these two services to perform external login)
Now as you mentioned, you need to support multiple oauth providers and since like Facebook not all providers use same configuration of oauth (they use different JWT attribute names, toke verification methods, etc. (Openid connect tries to unify this process)) i would suggest you to use some middleware identity provider like Oauth0 (service not protocol) or Keycloak. These can be used with external identity providers (Social pages as you mentioned) and also provides you with custom user store.
Advantage is that they unify authentication process under one type (e.g both support openid connect). Whereas when using multiple oauth providers with not unified authentication workflow you will end up with redudant implementations and need for merging different information's under one type (this is basically what mentioned middle-ware identity providers solve for you).
So if you will use only Facebook as identity provider in your app then go for it and make implementation directly for Facebook Oauth workflow. But with multiple identity providers (which is almost always case when creating public services) you should stick with mentioned workaround or find another one (or maybe wait till all social services will support Openid connect, which they probably wont).
There may be hope.. This year, Facebook have announced a "limited login" feature, which, if they were to add to their javascript sdks would certainly make my life easier:
https://developers.facebook.com/blog/post/2021/04/12/announcing-expanded-functionality-limited-login/
At the time of writing, I can only find reference to iOS and Unity SDKs, but it does seem to return a normal JWT, which is all I want!
Should a SAML federation software accept the same SAML response as long as it is within the allowed SAML token lifetime?
In simpler terms: IDP (identify provider) issues a SAML response, then SP (service provider) accepts/processes it. Can the same unmodified SAML response be then re-used immediately after the first use? Given that the SAML issuance timestamp is within allowed range.
Security-wise it makes sense to restrict a SAML token (response) to only one use, so that even if it is stolen by a "man-in-the-middle" - it cannot be reused. But in order to implement that, the software needs to store some info about the SAML response somewhere: serial number, a hash of the whole thing?
Please provide some links with the explanations on that is possible and/or examples of implementation.
Thank you!
Alex.
The SAML 2.0 norm provides another way to prevent replay attacks that do not imply storing in database the ID of the assertion.
The SP sends a request with an ID="X" and stores this ID in session.
The IDP authenticates the user and sends back a Response with an ID="Y" AND a InResponseTo="X" (which is also normally present in the assertion in the SubjectConfirmationData).
The SP gets the Response and check that all the InResponseTo values match the one in session. If not, the SP rejects the response.
The SP clears the ID in session, thus making replay of the Response impossible. In the ideal case, the SP should clear the ID in session as soon as it receives the response.
This check really complicates the replay attack, as an attacker will also need to have the session cookie of the SP (and even in this case, it's already game over anyway...).
It's also good practice to sign the whole response.
Obviously this method is only valid in a SP-initiated scenario.
Does it make sense, security-wise? Sure. And in fact you can use the "xs:ID" portion of an assertion to assist you (my company's software does).
From Page 9 of CORE:
The xs:ID simple type is used to declare SAML identifiers for
assertions, requests, and responses. Values declared to be of type
xs:ID in this specification MUST satisfy the following properties in
addition to those imposed by the definition of the xs:ID type itself:
• Any party that assigns an identifier MUST ensure that there is
negligible probability that that party or any other party will
accidentally assign the same identifier to a different data object.
• Where a data object declares that it has a particular identifier,
there MUST be exactly one such declaration.
We snatch that ID from an assertion, and drop it into an array with the not-after time, and then throw it out after that time expires. This way the same assertion can't be replayed.
In other software (especially home-grown stuff), this is entirely managed with the Not-Before and Not-On-Or-After portion of the Audience Restriction. Since some software counts solely on these values, the suggested method is to set this period as short as is reasonable. In the perfect world, everyone is using time servers, and their clock skew isn't more than a couple of seconds. A minute prior, and a minute post issue time should be far more than sufficient. While there isn't as much "security" here, it can be "managed".
I am working on a REST API for a web application that up until now we have developed internally for a couple of companion applications. Now that we are looking at opening up to outside developers we want to add tokens to the API in order to help identify who is making requests and in general to help manage it's use. At this point we are using https and basic authentication for user authentication on the API.
The token scheme we've been discussing would be very simple where each developer would be assigned 1 or more tokens and these tokens would be passed as a parameter with each request.
My question is if you've done something similar before how did you do it (did you do more or less, how did you handle security, etc) and do you have any recommendations?
First, you might want look at http://OAuth.net. Depending on your usecases, it might provide the security you need.
As to the token, it's a BLOB to most protocols, including OAuth. You can put any information you need in it in any format.
Here is what we do,
First we assign each developer a key with associated secret.
The token itself is an encrypted name-value pairs. We put things like username, expiry, session id, roles etc in there. It's encrypted with our own secret so no one else can make it.
For easy of use with web API, we use the URL-safe version of Base64 so the token is always URL-safe.
Hope that helps!
You might also want to think about maybe adding a time based token that would allow you to limit the amount of time a request is valid. this will help with someone trying to do a replay attack.
You would have a handshake call to get/assign a time valid token based off the above developerKey. This token would be stored locally and passed back to the caller.
The developer would then use this key in a request to validate the request and the developer.
For example that key can then be used for 5 mins or for 10 requests or whatever you define. after that point the generated time based token is removed from the valid list and can no longer be used. the developer will then have to ask for a new token.
UUID is very good for any temporary random key you fancy dishing out. Unpredictable and fast to generate, with collisions so unlikely they are effectively unique. Make nice session keys also.