[keycloak-dev] token service

Schuster Sebastian (INST/ESY1) Sebastian.Schuster at bosch-si.com
Wed Mar 15 03:30:48 EDT 2017


Have you seen the current version of [2] at https://tools.ietf.org/html/draft-ietf-oauth-token-exchange-07 ? This one looks very different and probably better...

Regards,
Sebastian

-----Ursprüngliche Nachricht-----
Von: keycloak-dev-bounces at lists.jboss.org [mailto:keycloak-dev-bounces at lists.jboss.org] Im Auftrag von Bill Burke
Gesendet: Dienstag, 14. März 2017 23:33
An: keycloak-dev <keycloak-dev at lists.jboss.org>
Betreff: [keycloak-dev] token service

There seems to be momentum building around token services, particular features around:

* Token downgrades.  Reducing the scope of an access token when delegating to a separate less trusted service.  For example, you have a token with admin priveleges and you want to remove those privleges before re-using the token against another service.

* Token exchanges.  Ability to convert a foreign token to and from a Keycloak one.  For example, if you want to trust tokens issued by some proprietary IBM IDM.

* Trusting tokens from other Keycloak domains.  (Although I think this can fall under token exchanges).

* Token revalidation (I think we have this).


There are some specs around this that Pedro pointed me to:

  [1]https://tools.ietf.org/html/draft-richer-oauth-chain-00
[2]https://tools.ietf.org/html/draft-campbell-oauth-sts-01
<https://tools.ietf.org/html/draft-campbell-oauth-sts-01>

I don't think they are either missing things we need or too complex for our needs.

* Token downgrades, or token redelgation/chaining

I don't want to require apps to know the exact scope they have to downgrade to if they want to reduce the scope when interacting with another service.  Let's provide an additional extension to [1] and supply a "client" parameter in which the clientId of the redelegation you want to perform is used.  The token returned would be a union of the access token's scope and the configured scope of the target client.

* Token exchanges
For [2] Keycloak just doesn't have all the concepts that are spoken about here.  I also don't think the spec is good enough. Coverting tokens would be handled by a Token Exchange SPI.  A provider would be configured per realm and implemented on top of the ComponentModel SPI.  
Each of these provider instances would handle either converting from an external token to a realm token and/or from a realm token to an external token.  There will also be a rest endpoint on the realm to convert from external to Keycloak and a separate REST endpoint for converting from Keycloak to an external token.

 From externl to Keycloka:
This would be a form POST to /token/convert-from with these additional form parameters

"token" - REQUIRED. string rep of the token "provider" - REQUIRED. id of transformer register in the realm for the token type "requested-token-type" - OPTIONAL.  "id", "access", "offline", or "refresh".  Default is "access".
"scope" - OPTIONAL.  Same as oauth scope.

This operation is analogous to the code to token flow.  Here we are creating a token tailored to the authenticated client.  So all scope configurations and mappers that the client has are applied. This means that the client must be registered as an OIDC client. The SPI would look something like this:

interface TokenExchangeFromProvider extends Provider {

     Transformer parse(ClientModel client, Map<String, String> formParameters);

     interface Transformer {

         UserModel getUser();
         IDToken convert(IDToken idToken);
         AccessToken convert(AccessToken accessToken);
     }
}

The getUser() method returns a user that was authenticated from the external token.  The convert() methods just gives the provider the flexibility to do further transformations on the returned token.

The runtime would do something like this:

ClientModel authenticatedClient = ...;
ComponentModel model = realm.getComponent(formParams.get("provider"));
TokenExchangeFromProvider provider =
session.getProvider(TokenExchangeFromProvider.class, model); Transformer transformer = provider.parse(formParams); UserModel user = transformer.getUser(); if (formParam.get("requested-token-type").equals("access")) {
    AccessToken accessToken = generateAccessToken(authenticatedClient,
user, ...);
    accessToken = transformer.convert(accessToken).
}

Something similar would be done for converting a Keycloak token to an external token:

This would be a form POST to /token/convert-to with these additional form parameters

"token" - REQUIRED. string rep of the token "provider" - REQUIRED. id of transformer register in the realm for the token type


interface TokenExchangeToProvider extends Provider {

     ResponseBuilder parse(ClientModel client, Map<String, String> 
formParameters);
}

Since we're crafting something for an external token system, we give the 
provider complete autonomy in crafting the HTTP response to this operation.













_______________________________________________
keycloak-dev mailing list
keycloak-dev at lists.jboss.org
https://lists.jboss.org/mailman/listinfo/keycloak-dev



More information about the keycloak-dev mailing list