mitreid-connect / OpenID-Connect-Java-Spring-Server

An OpenID Connect reference implementation in Java on the Spring platform.
Other
1.48k stars 765 forks source link

scopes/claims with dynamic values #1129

Open rustykrun opened 8 years ago

rustykrun commented 8 years ago

How can I define a scope having a static part, e.g. 'payment' and a dynamic one, e.g. amount, currency, etc., so the associated access token will authorize the composite scope : 'payment 5$'? In my case I may need to get the resource owner approval for a specific payment (scope with params) not for any payment (static scope). How to send this dynamic part of a scope to the IdP and get it back into a JWT?

Currently I'm attaching the payment details as param to the authorization request and use the structuredValue in the SystemScope to add the amount to the base scope.

A second idea would be to use custom claims, instead of structured scopes, to represent the dynamic part of the scope. Is this a more practical approach? But again, the claims values has to be provided by the client (e.g. a merchant app) when the user wants to check-out. How can this be done with the current implementation?

The JWT payload would look like that (just a draft):

 {
    "iss": "..."
    "aud": "..."
    "client_id": "..."
    "redirect_uri": "..."
    "scope": "openid payment",
    "state": "...",   
    "claims": { <-- payment details as custom claims
    "IBAN": "...",
    "amount": "5",
    "currency": "$"
    }
 }

These custom claims has to be shown to the user in the consent screen so the user have all the details about the transaction to be authorized.

PayPal which is using oath2 is doing something like this (see https://developer.paypal.com/docs/integration/direct/make-your-first-call/):

  1. it gets the access token with a generic scope:
{
  "scope":"https://api.paypal.com/v1/payments/.*",
  "access_token":"Access-Token",
  "token_type":"Bearer",
  "app_id":"APP-6XR95014SS315863X",
  "expires_in":28800
}
  1. then it sets the amount in the payload and use the above access_token to do the payment:
https://api.paypal.com/v1/payments/payment \
"Content-Type: application/json" \
"Authorization: Bearer Access-Token" \
payload {
  "transaction":{
      "amount":{
        "total":"7.47",
        "currency":"USD"
      }
  }
}

Doesn't that mean that the same access token will work with any amount since the amount is not part of the scope? Wouldn't be more secure to add the transaction details to the JWS access token payload instead of the resource access request especially for cases when ResourceServer is not embedded into the IdP/AuthServer?

jricher commented 8 years ago

First, note that most APIs out there use static scope strings. We'll be removing the structured scopes in a future revision of the server, possibly even 1.3, as they're not very widely used or needed. Your use case is one of the handful of examples where people have wanted to use a structured scope of some variety (originally it was added for the now-defunct BlueButton+ REST project).

But even with that in mind, it might be better to just have a custom authorization API parameter that your token granter knows how to deal with, and then have the API be able to manage that, much like the PayPal example above. All you'd need to do is carry the extra parameter through to either the token introspection response or the JWT payload (or both).

jricher commented 8 years ago

To comment on a previous edit of this issue (in case it comes up): The ID token never should have had the scopes of the access token copied into it in the first place, that was an implementation mistake that's since been corrected.

rustykrun commented 8 years ago

I manage to carry the extra params up to the tokenServices bean (DefaultOAuth2ProviderTokenService) which is using a tokenEnhancer (ConnectTokenEnhancer) to generate the JWT payload. Here I'm stuck as I can't find a way to plug into the tokenEnhancer and add the part that should deal with the custom params. Just to see it working I modified the ConnectTokenEnhancer and add the extra params as claims with the jwtclaims builder, but of course this is just a hack. Maybe if ConnectTokenEnhancer would be a TokenEnhancerChain I could add my custom token enhancer to the chain. Another approach would be to overlay the ConnectTokenEnhancer, but was it intended for that in the first place? Do you see a different way to solve this?

jricher commented 7 years ago

Just a note that structured scopes have been removed on the 1.3 branch.