-
Notifications
You must be signed in to change notification settings - Fork 34
Create OAuth2 two-legged flow with user identifier associated with the access token #277
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
@AxelNennker, on the second option:
Instead of creating a new OAuth2 grant-type, couldn't we re-use OAuth2 Client Credential grant-type to additionally include the target-device/target-user identifier within the scope parameter. The scope parameter has been already enhanced in current grant-types to include dpv:purpose. So, including the target-device identifier would still be OAuth2 compliant and be much simpler than coming up with new grant-type. As long as the Authorization Server is able to understand this, I believe the OAuth2 framework would not restrict this enhancement of scope parameter in the Client Credential grant-type. So, the access-token request could look something like this,
and like CIBA, |
@subha5h thanks for the proposal. Putting the user identifier into the OAuth2 client credentials flow scope parameter was exactly my though as well. Maybe others want to keep the two-legged CIBA flow because it is already implemented by some. I think going the OAuth2 way is cleaner and that is my preferred solution. Also because there is one less network request. I would just go for |
I would propose using the |
Yes, refreshtokens are the standard way to get a new access token without new user authentication. Users do not have to re-authenticate every time an access token expires. The API Consumer can use the current refreshtoken to get a new valid access token and SHOULD get a new refreshtoken. Aside from that, law can require that the user authenticates from time to time. German Banking regulation, for example, requires a new strong authentication every 90 day. I think that is based on PSD2 requirements. Everybody, please also read https://datatracker.ietf.org/doc/html/rfc9700#name-refresh-token-protection on refresh tokens. Even if the API Consumer does not use their current refresh token, that does not mean that the user has to authenticate. In CIBA there are usually no cookies, but then id_token_hint or login_hint_token can be used as a replacement. |
I agree. These are off-the-shelf features from most of the OP providers. Sender Constrained Refresh token enforcement is straight forward with mTLS as CIBA requests are usually sent from backend.
Are we proposing this as a work around to avoid the authentication leg during While I agree on short term disruption for some providers on their interpretation, but long-term, we should prioritize standards compliance and interoperability to avoid fragmentation and vendor lock-in. |
This issue proposes the creation of a flow that creates an access token that is associated with a user identifier, and thus the access token is restricted to that user identifer. Usually in OAuth2 client_credential flows the client acts on its own behalf and is not restricted. If we had an OAuth2 client-credentials-based flow, where the access token is associated with an user identifier, then it would be clear to the API Consumer and the API Provider that this flow is two-legged. In the proposed flow there would be no id_token. If the API Consumer had an id_token, then they could use CIBA - if CAMARA would allow id_token_hint. In CIBA with id_token_hint the API Provider can decide whether they accept expired id_tokens, that is a policy decision. In the proposed flow there would be no room for interpretation whether the flow is two-legged or three-legged. |
Calling it 2-legged CIBA is an opinion, and it is arguable. As discussed over the past few weeks, some WG participants have pointed out that the existing documented flow does not strictly make CIBA a two-legged flow, since the user rights to opt-in (user is explicitly authenticated in this case) and opt-out (consent revocation is checked on every auth request) are still maintained, and the access token is indeed associated with the user identifier (the access token contains the three legs, client, auth server and user).
On the other hand, I think that the proposed changes in #268 could potentially solve issue #258 by not requiring another alternative flow to be defined. The proposed changes are based on not contradicting CIBA, but also not going beyond CIBA itself. However, if the WG still considers this alternative flow, from Telefónica's point of view we believe that the right way to do it would be to use JWTs as Authorization Grants ("urn:ietf:params:oauth:grant-type:jwt-bearer" grant_type for Oauth 2.0) that provide a JWT assertion following the OAuth Assertion Framework: Using Assertions as Authorization Grants | Client Acting on Behalf of a User. For example:
JWT Bearer grant is the flow that actually allows user-associated tokens (three-legged tokens) to be obtained by delegating authentication to the client, which is sufficiently compromised so that the delegated authentication can be certified by the client in an assertion with its associated signature. In contrast, extending Client Credentials to achieve similar functionality is not advisable IMHO. The Client Credentials grant type specification lacks mechanisms for assertions or for associating tokens with user identifiers. Attempting to retrofit such capabilities would represent a significant and arguably confusing extension, effectively creating a less coherent and potentially redundant alternative to the well-established JWT Bearer grant. This approach seems less aligned with standard OAuth 2.0 practices and could introduce unnecessary complexity. In summary, we recommend that the changes proposed in PR #268 be adopted. If an alternative is still pursued, JWT Bearer grant provides a standards-based and secure approach. Extending Client Credentials for this purpose is less technically sound and conceptually misaligned. We are open to further discussion within the WG to clarify these points. |
Access token documented in Camara CIBA flow might be 3-legged. I believe, the disagreement is not on the access token being 2-legged, but on "Whether the CIBA flow described in Camara today & the access token issued is complaint with Open Id CIBA specification when no authentication is done during auth flow?". If consent capture is needed, authentication would be done during the flow, which may align with standard Open Id CIBA flow.
So, within Camara WG we may still agree to keep the CIBA flow as it is. But would it still be compliant with Open Id or "would it be a Camara variant of Open Id CIBA flow"?
|
OIDC and CAMARA are using RFC7523 already. OIDC https://openid.net/specs/openid-connect-core-1_0.html#ClientAuthentication:~:text=OAuth.JWT%5D.-,private_key_jwt,-Clients%20that%20have The difference between the OIDC usage in private_key_jwt and the original RFC7523 seems to be that RFC7523 uses "sub" to identify the user while OIDC uses sub to identify the client. It is simple to create a PR to CAMARA-Security-Interoperability.md that says something like: |
This is confusing very different things... The assertions can be used either for client authentication or, in this case, as an authorization grant. CAMARA already uses them for the former (private_key_jwt) and also for the signed request object (signed authentication requests), but these assertions are independent and can't be mixed. |
Couldn't the same assertion be used for both client authentication and authorization? and to do that in Camara, I assume we just need to overrule the below OIDC recommendation and use sub claim for
|
Yes, those are different things. The OAuth2 Access Token Request example looks like this:
The example from RFC7523 looks like this:
OAuth2 client authentication says:
The CAMARA API Provider's Authorization Server could accept this form of client authentication example (with extra line breaks for display purposes only):
The bearer token would be the signed and encrypted JWT from RFC7523. {
"iss": "https://backend.api-consumer.com",
"sub": "tel:+353876158815 ,
"aud": "https://az.api-provider.com",
"nbf": 1300815780,
"exp": 1300819380,
"iat": 1300819080
} I think RFC7523 was created because the IEFT oauth WG did not want to touch three years young OAuth2 standard. I guess it is "cleaner" to use RFC7523 as a two-legged flow. |
Based on the RFC7523 standard and existing CAMARA specifications, the process involves two distinct JWT (JSON Web Token) assertions for client authentication and authorization grant. Firstly, for client authentication, CAMARA mandates the use of Secondly, an authorization grant is also required. This is a separate JWT assertion used to grant access. It is provided in the authentication request using the Therefore, if we stick to the standard, the authentication request necessitates two different JWT assertions serving distinct purposes: one for authenticating the client and the other for representing the authorization grant. Here is how the authentication request would look:
Note that this follows existing standards without deviation. The only additional detail CAMARA would need to specify is how to fill the Client assertion payload example: {
"iss": "client_id",
"sub": "client_id",
"aud": "https://az.api-provider.com",
"exp": 1504807731,
"iat": 1504804131,
"jti": "53f42eb1-b751-44b5-bada-6990e08f35ad"
} Authorization grant assertion payload example: {
"iss": "client_id",
"sub": "tel:+34666666666",
"aud": "https://az.api-provider.com",
"exp": 1504807731,
"iat": 1504804131,
"jti": "53f42eb1-b751-44b5-bada-6990e08f35ac"
} It's worth noting that since the authorization grant assertion is also signed using the client's key (identified by the client_id in its iss claim), the client's signature is also effectively validated by this assertion. This suggests a potential redundancy in requiring a separate client assertion, so depending on the specific security requirements and trust model, it could be allowed not to send it. |
+1 for not sending the client assertion IF we do this. I think semantically it is the same whether the assertion is send in an HTTP Authorization header or as an assertion post parameter. I would suggest to add the grant_typ as a "typ" to the assertion to make sure what is is. {
"typ": "urn:ietf:params:oauth:grant-type:jwt-bearer"
"iss": "client_id",
"sub": "tel:+34666666666",
"aud": "https://az.api-provider.com",
"exp": 1504807731,
"iat": 1504804131,
"jti": "53f42eb1-b751-44b5-bada-6990e08f35ac"
} I believe that API gateways are easier to configure to validate Authorization headers, but that is just a guess on my behalf. |
@AxelNennker, I do not think it is necessary to send the claim |
@AxelNennker thank you for raising this. From an aggregator/channel partner perspective this will ensure API adoption for backend APIs that do not require end user consent (e.g. SIM Swap). |
Please see #268 (comment) The flow I proposed there uses the signed request object as a client assertion and the login_hint=operatortoken: as the User assertion. I think that API providers who currently have CIBA implementations already can adapt to this flow quite easily. |
@AxelNennker One of the problems I see with creating yet another flow with an access token tied to a specific user, is that such a flow is inherently slow, because such an access token can only be created at the time the resource call is needed to be executed. If your main worry about why the token should be tied to a specific number is privacy or security, there may also be other options to reduce the possibility to abuse tokens, simply by restricting how many times a token can be used, and potentially how many tokens an API Consumer may have collected (to be used in the next hours or so). In its simplest form, for a specific client_id you allow the API Consumer to have one token in stock (or in a cache), and which can be used for any next resource call. That way you keep the moment of when the token is retrieved separate from when the resource call is being executed. This way you can also address the use cases where you need sub 100ms latencies. For API Consumers that have a lot of traffic, you can also agree that they can hold more than one token in stock if that becomes a bottle neck. I think this method will also address some of the privacy concerns, but will give a much shorter latency at the time of a transaction. |
Problem description
There is a need for an access token that is created by a two-legged flow (OAuth2 client credentials) but that access token is associated with a user identifier (API target).
As stated in #268 the current CIBA description is a two-legged flow, although CIBA as standardized as a three-legged flow.
Basically the CIBA flow as described solves this issue, but it is easy that that two-legged CIBA can too easily be misunderstood as a three-legged flow which it is not.
Possible evolution
I think there are two ways forward.
This would have the advantage, that we do not have to talk about polling etc because the new flow would create the access token in one call.
The text was updated successfully, but these errors were encountered: