diff --git a/securing_apps/keycloak-images/exchange-idp-apply-policy.png b/securing_apps/keycloak-images/exchange-idp-apply-policy.png new file mode 100644 index 0000000000..06e20b3fa6 Binary files /dev/null and b/securing_apps/keycloak-images/exchange-idp-apply-policy.png differ diff --git a/securing_apps/keycloak-images/exchange-idp-client-policy.png b/securing_apps/keycloak-images/exchange-idp-client-policy.png new file mode 100644 index 0000000000..9a88cb4ac2 Binary files /dev/null and b/securing_apps/keycloak-images/exchange-idp-client-policy.png differ diff --git a/securing_apps/keycloak-images/exchange-idp-permission-set.png b/securing_apps/keycloak-images/exchange-idp-permission-set.png new file mode 100644 index 0000000000..adc644b2f6 Binary files /dev/null and b/securing_apps/keycloak-images/exchange-idp-permission-set.png differ diff --git a/securing_apps/keycloak-images/exchange-idp-permission-setup.png b/securing_apps/keycloak-images/exchange-idp-permission-setup.png new file mode 100644 index 0000000000..5e1586360f Binary files /dev/null and b/securing_apps/keycloak-images/exchange-idp-permission-setup.png differ diff --git a/securing_apps/keycloak-images/exchange-idp-permission-unset.png b/securing_apps/keycloak-images/exchange-idp-permission-unset.png new file mode 100644 index 0000000000..23aa116dd2 Binary files /dev/null and b/securing_apps/keycloak-images/exchange-idp-permission-unset.png differ diff --git a/securing_apps/keycloak-images/exchange-target-client-exchange-apply-policy.png b/securing_apps/keycloak-images/exchange-target-client-exchange-apply-policy.png new file mode 100644 index 0000000000..415d3ed6ab Binary files /dev/null and b/securing_apps/keycloak-images/exchange-target-client-exchange-apply-policy.png differ diff --git a/securing_apps/keycloak-images/exchange-target-client-permission-set.png b/securing_apps/keycloak-images/exchange-target-client-permission-set.png new file mode 100644 index 0000000000..f7f8482c6c Binary files /dev/null and b/securing_apps/keycloak-images/exchange-target-client-permission-set.png differ diff --git a/securing_apps/keycloak-images/exchange-target-client-permission-setup.png b/securing_apps/keycloak-images/exchange-target-client-permission-setup.png new file mode 100644 index 0000000000..4be2aad650 Binary files /dev/null and b/securing_apps/keycloak-images/exchange-target-client-permission-setup.png differ diff --git a/securing_apps/keycloak-images/exchange-target-client-permission-unset.png b/securing_apps/keycloak-images/exchange-target-client-permission-unset.png new file mode 100644 index 0000000000..ffb3516aee Binary files /dev/null and b/securing_apps/keycloak-images/exchange-target-client-permission-unset.png differ diff --git a/securing_apps/keycloak-images/exchange-target-client-policy.png b/securing_apps/keycloak-images/exchange-target-client-policy.png new file mode 100644 index 0000000000..dc5ed8ec16 Binary files /dev/null and b/securing_apps/keycloak-images/exchange-target-client-policy.png differ diff --git a/securing_apps/keycloak-images/exchange-users-apply-policy.png b/securing_apps/keycloak-images/exchange-users-apply-policy.png new file mode 100644 index 0000000000..f0db3aea86 Binary files /dev/null and b/securing_apps/keycloak-images/exchange-users-apply-policy.png differ diff --git a/securing_apps/keycloak-images/exchange-users-client-policy.png b/securing_apps/keycloak-images/exchange-users-client-policy.png new file mode 100644 index 0000000000..b04bfb3c01 Binary files /dev/null and b/securing_apps/keycloak-images/exchange-users-client-policy.png differ diff --git a/securing_apps/keycloak-images/exchange-users-permission-set.png b/securing_apps/keycloak-images/exchange-users-permission-set.png new file mode 100644 index 0000000000..7220740bcb Binary files /dev/null and b/securing_apps/keycloak-images/exchange-users-permission-set.png differ diff --git a/securing_apps/keycloak-images/exchange-users-permission-setup.png b/securing_apps/keycloak-images/exchange-users-permission-setup.png new file mode 100644 index 0000000000..031aa52c0c Binary files /dev/null and b/securing_apps/keycloak-images/exchange-users-permission-setup.png differ diff --git a/securing_apps/keycloak-images/exchange-users-permission-unset.png b/securing_apps/keycloak-images/exchange-users-permission-unset.png new file mode 100644 index 0000000000..d51f5ae147 Binary files /dev/null and b/securing_apps/keycloak-images/exchange-users-permission-unset.png differ diff --git a/securing_apps/rhsso-images/exchange-idp-apply-policy.png b/securing_apps/rhsso-images/exchange-idp-apply-policy.png new file mode 100644 index 0000000000..d9a5838d70 Binary files /dev/null and b/securing_apps/rhsso-images/exchange-idp-apply-policy.png differ diff --git a/securing_apps/rhsso-images/exchange-idp-client-policy.png b/securing_apps/rhsso-images/exchange-idp-client-policy.png new file mode 100644 index 0000000000..d7edf04159 Binary files /dev/null and b/securing_apps/rhsso-images/exchange-idp-client-policy.png differ diff --git a/securing_apps/rhsso-images/exchange-idp-permission-set.png b/securing_apps/rhsso-images/exchange-idp-permission-set.png new file mode 100644 index 0000000000..305d7a5ec3 Binary files /dev/null and b/securing_apps/rhsso-images/exchange-idp-permission-set.png differ diff --git a/securing_apps/rhsso-images/exchange-idp-permission-setup.png b/securing_apps/rhsso-images/exchange-idp-permission-setup.png new file mode 100644 index 0000000000..84818f410d Binary files /dev/null and b/securing_apps/rhsso-images/exchange-idp-permission-setup.png differ diff --git a/securing_apps/rhsso-images/exchange-idp-permission-unset.png b/securing_apps/rhsso-images/exchange-idp-permission-unset.png new file mode 100644 index 0000000000..34b5d0e520 Binary files /dev/null and b/securing_apps/rhsso-images/exchange-idp-permission-unset.png differ diff --git a/securing_apps/rhsso-images/exchange-target-client-exchange-apply-policy.png b/securing_apps/rhsso-images/exchange-target-client-exchange-apply-policy.png new file mode 100644 index 0000000000..ad2c42ed84 Binary files /dev/null and b/securing_apps/rhsso-images/exchange-target-client-exchange-apply-policy.png differ diff --git a/securing_apps/rhsso-images/exchange-target-client-permission-set.png b/securing_apps/rhsso-images/exchange-target-client-permission-set.png new file mode 100644 index 0000000000..e3341ddbe9 Binary files /dev/null and b/securing_apps/rhsso-images/exchange-target-client-permission-set.png differ diff --git a/securing_apps/rhsso-images/exchange-target-client-permission-setup.png b/securing_apps/rhsso-images/exchange-target-client-permission-setup.png new file mode 100644 index 0000000000..18219c8e7d Binary files /dev/null and b/securing_apps/rhsso-images/exchange-target-client-permission-setup.png differ diff --git a/securing_apps/rhsso-images/exchange-target-client-permission-unset.png b/securing_apps/rhsso-images/exchange-target-client-permission-unset.png new file mode 100644 index 0000000000..56f787c786 Binary files /dev/null and b/securing_apps/rhsso-images/exchange-target-client-permission-unset.png differ diff --git a/securing_apps/rhsso-images/exchange-target-client-policy.png b/securing_apps/rhsso-images/exchange-target-client-policy.png new file mode 100644 index 0000000000..eb132ae8e0 Binary files /dev/null and b/securing_apps/rhsso-images/exchange-target-client-policy.png differ diff --git a/securing_apps/rhsso-images/exchange-users-apply-policy.png b/securing_apps/rhsso-images/exchange-users-apply-policy.png new file mode 100644 index 0000000000..1b7a3c84e4 Binary files /dev/null and b/securing_apps/rhsso-images/exchange-users-apply-policy.png differ diff --git a/securing_apps/rhsso-images/exchange-users-client-policy.png b/securing_apps/rhsso-images/exchange-users-client-policy.png new file mode 100644 index 0000000000..df038d3589 Binary files /dev/null and b/securing_apps/rhsso-images/exchange-users-client-policy.png differ diff --git a/securing_apps/rhsso-images/exchange-users-permission-set.png b/securing_apps/rhsso-images/exchange-users-permission-set.png new file mode 100644 index 0000000000..2086423405 Binary files /dev/null and b/securing_apps/rhsso-images/exchange-users-permission-set.png differ diff --git a/securing_apps/rhsso-images/exchange-users-permission-setup.png b/securing_apps/rhsso-images/exchange-users-permission-setup.png new file mode 100644 index 0000000000..40e3bb2a7f Binary files /dev/null and b/securing_apps/rhsso-images/exchange-users-permission-setup.png differ diff --git a/securing_apps/rhsso-images/exchange-users-permission-unset.png b/securing_apps/rhsso-images/exchange-users-permission-unset.png new file mode 100644 index 0000000000..01c9a4521d Binary files /dev/null and b/securing_apps/rhsso-images/exchange-users-permission-unset.png differ diff --git a/securing_apps/topics.adoc b/securing_apps/topics.adoc index 04faff4f75..6ddcdaadca 100644 --- a/securing_apps/topics.adoc +++ b/securing_apps/topics.adoc @@ -91,3 +91,4 @@ include::topics/saml/mod-auth-mellon.adoc[] include::topics/docker/docker-overview.adoc[] include::topics/client-registration.adoc[] include::topics/client-registration/client-registration-cli.adoc[] +include::topics/token-exchange/token-exchange.adoc[] diff --git a/securing_apps/topics/token-exchange/token-exchange.adoc b/securing_apps/topics/token-exchange/token-exchange.adoc new file mode 100644 index 0000000000..cdb705d04a --- /dev/null +++ b/securing_apps/topics/token-exchange/token-exchange.adoc @@ -0,0 +1,463 @@ + +[[_token-exchange]] + +== Token Exchange + +In {project_name}, token exchange is the process of using a set of credentials or token to obtain an entirely different token. +A client may want to invoke on a less trusted application so it may want to downgrade the current token it has. +A client may want to exchange a {project_token} for a token stored for a linked social provider account. +You may want to trust external tokens minted by other {project_name} realms or foreign IDPs. A client may have a need +to impersonate a user. Here's a short summary of the current capabilities of {project_name} around token exchange. + +* A client can exchange an existing {project_name} token created for a specific client for a new token targeted to a different client +* A client can exchange an existing {project_name} token for an external token, i.e. a linked Facebook account +* A client can exchange an external token for a {project_name} token. +* A client can impersonate a user + +Token exchange in {project_name} is a very loose implementation of the link:http://www.ietf.org/id/draft-ietf-oauth-token-exchange-09.txt[OAuth Token Exchange] specification at the IETF. +We have extended it a little, ignored some of it, and loosely interpreted other parts of the specification. It is +a simple grant type invocation on a realm's OpenID Connect token endpoint. + +---- +/realms/{realm}/protocol/openid-connect/token +---- + +It accepts form parameters (`application/x-www-form-urlencoded`) as input and the output depends on the type of token you requested an exchange for. +Token exchange is a client endpoint so requests must provide authentication information for the calling client. +Public clients specify their client identifier as a form parameter. Confidential clients can also use form parameters +to pass their client id and secret, Basic Auth, or however your admin has configured the client authentication flow in your +realm. Here's a list of form parameters + +client_id:: + _REQUIRED MAYBE._ This parameter is required for clients using form parameters for authentication. If you are using + Basic Auth, a client JWT token, or client cert authentication, then do not specify this parameter. +client_secret:: + _REQUIRED MAYBE_. This parameter is required for clients using form parameters for authentication and using a client secret as a credential. + Do not specify this parameter if client invocations in your realm are authenticated by a different means. + +grant_type:: + _REQUIRED._ The value of the parameter must be `urn:ietf:params:oauth:grant-type:token-exchange`. +subject_token:: + _OPTIONAL._ A security token that represents the identity of the party on behalf of whom the request is being made. It is required if you are exchanging an existing token for a new one. +subject_issuer:: + _OPTIONAL._ Identifies the issuer of the `subject_token`. It can be left blank if the token comes from the current realm or if the issuer + can be determined from the `subject_token_type`. Otherwise it is required to be specified. Valid values are the alias of an `Identity Provider` configured for your realm. Or an issuer claim identifier + configured by a specific `Identity Provider`. +subject_token_type:: + _OPTIONAL._ This parameter is the type of the token passed with the `subject_token` parameter. This defaults + to `urn:ietf:params:oauth:token-type:access_token` if the `subject_token` comes from the realm and is an access token. + If it is an external token, this parameter may or may not have to be specified depending on the requirements of the + `subject_issuer`. +requested_token_type:: + _OPTIONAL._ This parameter represents the type of token the client wants to exchange for. Currently only oauth + and OpenID Connect token types are supported. The default value for this depends on whether the + is `urn:ietf:params:oauth:token-type:refresh_token` in which case you will be returned both an access token and refresh + token within the response. Other appropriate values are `urn:ietf:params:oauth:token-type:access_token` and `urn:ietf:params:oauth:token-type:id_token` +audience:: + _OPTIONAL._ This parameter specifies the target client you want the new token minted for. +requested_issuer:: + _OPTIONAL._ This parameter specifies that the client wants a token minted by an external provider. It must + be the alias of an `Identity Provider` configured within the realm. +requested_subject:: + _OPTIONAL._ This specifies a username or user id if your client wants to impersonate a different user. +scope:: + _NOT IMPLEMENTED._ This parameter represents the target set of OAuth and OpenID Connect scopes the client + is requesting. It is not implemented at this time but will be once {project_name} has better support for + scopes in general. + +NOTE: We currently only support OpenID Connect and OAuth exchanges. Support for SAML based clients and identity providers may be added in the future depending on user demand. + +A successful response from an exchange invocation will return the HTTP 200 response code with a content type that +depends on the `requested-token-type` and `requested_issuer` the client asks for. OAuth requested token types will return +a JSON document as described in the link:http://www.ietf.org/id/draft-ietf-oauth-token-exchange-09.txt[OAuth Token Exchange] specification. + +---- +{ + "access_token" : ".....", + "refresh_token" : ".....", + "expires_in" : "...." + } +---- + +Clients requesting a refresh token will get back both an access and refresh token in the response. Clients requesting only +access token type will only get an access token in the response. Expiration information may or may not be included for +clients requesting a an external issuer through the `requested_issuer`paramater. + +Error responses generally fall under the 400 HTTP response code category, but other error status codes may be returned +depending on the severity of the error. Error responses may include content depending on the `requested_issuer`. +OAuth based exchanges may return a JSON document as follows: + +---- +{ + "error" : "...." + "error_description" : "...." +} +---- + +Additional error claims may be returned depending on the exchange type. For example, OAuth Identity Providers may include +an additional `account-link-url` claim if the user does not have a link to an identity provider. This link can be used +for a client initiated link request. + +NOTE: Token exchange setup requires knowledge of fine grain admin permissions (See the link:{adminguide_link}[{adminguide_name}] for more information). You will need to grant clients + permission to exchange. This is discusssed more later in this chapter. + +The rest of this chapter discusses the setup requirements and provides examples for different exchange scenarios. +For simplicity's sake, let's call a token minted by the current realm as an _internal_ token and a token minted by +an external realm or identity provider as an _external_ token. + + +=== Internal Token to Internal Token Exchange + +With an internal token to token exchange you have an existing token minted to a specific client and you want to exchange +this token for a new one minted for a different target client. Why would you want to do this? This generally happens +when a client has a token minted for itself, and needs to make additional requests to other applications that require different +claims and permissions within the access token. Other reasons this type of exchange might be required is if you +need to perform a "permission downgrade" where your app needs to invoke on a less trusted app and you don't want +to propagate your current access token. + +[[_client_to_client_permission]] +==== Granting Permission for the Exchange + +Clients that want to exchange tokens for a different client need to be authorized in the admin console to do so. +You'll need to define a `token-exchange` fine grain permission in the target client you want permission to exchange to. + +.Target Client Permission +image:{project_images}/exchange-target-client-permission-unset.png[] + +Toggle the `Permissions Enabled` switch to true. + +.Target Client Permission +image:{project_images}/exchange-target-client-permission-set.png[] + +You should see a `token-exchange` link on the page. Click that to start defining the permission. It will bring you +to this page. + +.Target Client Exchange Permission Setup +image:{project_images}/exchange-target-client-permission-setup.png[] + +You'll have to define a policy for this permission. Click the `Authorization` link, go to the `Policies` tab and create +a `Client` Policy. + +.Client Policy Creation +image:{project_images}/exchange-target-client-policy.png[] + +Here you enter in the starting client, that is the authenticated client that is requesting a token exchange. After you +create this policy, go back to the target client's `token-exchange` permission and add the client policy you just +defined. + +.Apply Client Policy +image:{project_images}/exchange-target-client-exchange-apply-policy.png[] + +Your client now has permission to invoke. If you do not do this correctly, you will get a 403 Forbidden response if you +try to make an exchange. + +==== Making the Request + +When your client is exchanging an existing token for a token targeting another client, you must use the `audience` parameter. +This parameter must be the client identifier for the target client that you configured in the admin console. + +[source,bash] +---- +curl -X POST \ + -d "client_id=starting-client" \ + -d "client_secret=geheim" \ + --data-urlencode "grant_type=urn:ietf:params:oauth:grant-type:token-exchange" \ + -d "subject_token=...." \ + --data-urlencode "requested_token_type=urn:ietf:params:oauth:token-type:refresh_token" + -d "audience=target-client" \ + http://localhost:8080/auth/realms/myrealm/protocol/openid-connect/token +---- + + +The `subject_token` parameter must be an access token for the target realm. If your `requested_token_type` parameter +is a refresh token type, then the response will contain both an access token, refresh token, and expiration. Here's +an example JSON response you get back from this call. + +[source,json] +---- +{ + "access_token" : "....", + "refresh_token" : "....", + "expires_in" : 3600 +} +---- + +=== Internal Token to External Token Exchange + +You can exchange a realm token for an externl token minted by an external identity provider. This external identity provider +must be configured within the `Identity Provider` section of the admin console. Currently only OAuth/OpenID Connect based external +identity providers are supported, this includes all social providers. {project_name} does not perform a backchannel exchange to the external provider. So if the account +is not linked, you will not be able to get the external token. To be able to obtain an external token one of +these conditions must be met: + +* The user must have logged in with the external identity provider at least once +* The user must have linked with the external identity provider through the User Account Service +* The user account was linked through the external identity provider using link:{developerguide_link}[Client Initiated Account Linking] API. + +Finally, the external identity provider must have been configured to store tokens, or, one of the above actions must +have been performed with the same user session as the internal token you are exchanging. + +If the account is not linked, the exchange response will contain a link you can use to establish it. This is +discussed more in the <<_internal_external_making_request, Making the Request>> section. + +[[_grant_permission_external_exchange]] +==== Granting Permission for the Exchange + +Internal to external token exchange requests will be denied with a 403, Forbidden response until you grant +permission for the calling client to exchange tokens with the external identity provider. To grant permission +to the client you must go to the identity provider's configuration page to the `Permissions` tab. + +.Identity Provider Permission +image:{project_images}/exchange-idp-permission-unset.png[] + +Toggle the `Permissions Enabled` switch to true. + +.Identity Provier Permission +image:{project_images}/exchange-idp-permission-set.png[] + +You should see a `token-exchange` link on the page. Click that to start defining the permission. It will bring you +to this page. + +.Identity Provider Exchange Permission Setup +image:{project_images}/exchange-idp-permission-setup.png[] + +You'll have to define a policy for this permission. Click the `Authorization` link, go to the `Policies` tab and create +a `Client` Policy. + +.Client Policy Creation +image:{project_images}/exchange-idp-client-policy.png[] + +Here you enter in the starting client, that is the authenticated client that is requesting a token exchange. After you +create this policy, go back to the identity providers's `token-exchange` permission and add the client policy you just +defined. + +.Apply Client Policy +image:{project_images}/exchange-idp-apply-policy.png[] + +Your client now has permission to invoke. If you do not do this correctly, you will get a 403 Forbidden response if you +try to make an exchange. + +[[_internal_external_making_request]] +==== Making the Request + +When your client is exchanging an existing internal token to an external one, you must provide the +`requested_issuer` parameter. The parameter must be the alias of a configured identity provider. + +[source,bash] +---- +curl -X POST \ + -d "client_id=starting-client" \ + -d "client_secret=geheim" \ + --data-urlencode "grant_type=urn:ietf:params:oauth:grant-type:token-exchange" \ + -d "subject_token=...." \ + --data-urlencode "requested_token_type=urn:ietf:params:oauth:token-type:refresh_token" + -d "requested_issuer=google" \ + http://localhost:8080/auth/realms/myrealm/protocol/openid-connect/token +---- + + +The `subject_token` parameter must be an access token for the target realm. The `requested_token_type` parameter +must be `urn:ietf:params:oauth:token-type:access_token` or left blank. No other requested token type is supported +at this time. Here's +an example successful JSON response you get back from this call. + +[source,json] +---- +{ + "access_token" : "....", + "expires_in" : 3600 + "account-link-url" : "https://...." +} +---- + +If the external identity provider is not linked for whatever reason, you will get an HTTP 400 response code with +this JSON document: + +[source,json] +---- +{ + "error" : "....", + "error_description" : "..." + "account-link-url" : "https://...." +} +---- + +The `error` claim will be either `token_expired` or `not_linked`. The `account-link-url` claim is provided +so that the client can perform link:{developerguide_link}[Client Initiated Account Linking]. Most (all?) +providers requiring linking through browser OAuth protocol. With the `account-link-url` just add a `redirect_uri` +query parameter to it and you can forward browsers to perform the link. + +=== External Token to Internal Token Exchange + +You can trust and exchange external tokens minted by external identity providers for internal tokens. This can be +used to bridge between realms or just to trust tokens from your social provider. It works similarly to an identity provider +browser login in that a new user is imported into your realm if it doesn't exist. + +NOTE: The current limitation on external token exchanges is that if the external token maps to an existing user an + exchange will not be allowed unless the existing user already has an account link to the external identity + provider. + +When the exchange is complete, a user session will be created within the realm, and you will receive an access +and or refresh token depending on the `requested_toke_type` parameter value. You should note that this new +user session will remain active until it times out or until you call the logout endpoint of the realm passing this +new access token. + +These types of changes required a configured identity provider in the admin console. + +NOTE: Only OIDC identity providers are support at this time. Validate signatures switch is required and you must + provide either the public key to validate external token signatures, or a valid key URL to lookup key + identifiers contained in the token. + + +==== Granting Permission for the Exchange + +Before external token exchanges can be done, you must grant permission for the calling client to make the exchange. This +permission is granted in the same manner as <<_grant_permission_external_exchange, interal to external permission is granted>>. + +If you also provide an `audience` parameter whose value points to a different client other than the calling one, you +must also grant the calling client permission to exchange to the target client specific in the `audience` parameter. How +to do this is <<_client_to_client_permission, discussed earlier>> in this section. + +==== Making the Request + +When your client is exchanging an existing internal token to an external one, you must provide the +`subject_issuer` parameter. This parameter must be the alias of a configured identity provider. The +`subject_token_type` parameter must be specified and either be an identity token, `urn:ietf:params:oauth:token-type:id_token`, +or a JWT access token type `urn:ietf:params:oauth:token-type:jwt:access_token`. The `subject_token` must be a JWT +irregardless and must be signed using Json Web Signatures. + +By default, the internal token minted will use the calling client to determine what's in the token using the protocol +mappers defined for the calling client. Alternatively, you can specify a different target client using the `audience` +parameter. + +[source,bash] +---- +curl -X POST \ + -d "client_id=starting-client" \ + -d "client_secret=geheim" \ + --data-urlencode "grant_type=urn:ietf:params:oauth:grant-type:token-exchange" \ + -d "subject_token=...." \ + -d "subject_issuer=myOidcProvider" \ + --data-urlencode "subject_token_type=urn:ietf:params:oauth:token-type:id_token" + -d "audience=target-client" \ + http://localhost:8080/auth/realms/myrealm/protocol/openid-connect/token +---- + + +If your `requested_token_type` parameter +is a refresh token type, then the response will contain both an access token, refresh token, and expiration. Here's +an example JSON response you get back from this call. + +[source,json] +---- +{ + "access_token" : "....", + "refresh_token" : "....", + "expires_in" : 3600 +} +---- + + +=== Impersonation + +For internal and external token exchanges, the client can request on behalf of a user to impersonate a different user. +For example, you may have an admin application that needs to impersonate a user so that a support engineer can debug +a problem. + + +==== Granting Permission for the Exchange + +The user that the subject token represents must have permission to impersonate other users. See the +link:{adminguide_link}[{adminguide_name}] on how to enable this permission. It can be done through a role or through +fine grain admin permissions. + + +==== Making the Request + +Make the request as described in other chapters except additionally specify the `request_subject` parameter. The +value of this parameter must be a username or user id. + +[source,bash] +---- +curl -X POST \ + -d "client_id=starting-client" \ + -d "client_secret=geheim" \ + --data-urlencode "grant_type=urn:ietf:params:oauth:grant-type:token-exchange" \ + -d "subject_token=...." \ + --data-urlencode "requested_token_type=urn:ietf:params:oauth:token-type:refresh_token" \ + -d "audience=target-client" \ + -d "requested_subject=wburke" \ + http://localhost:8080/auth/realms/myrealm/protocol/openid-connect/token +---- + +=== Direct Naked Impersonation + +You can make an internal token exchange request without providing a `subject_token`. This is called a direct +naked impersonation because it places a lot of trust in a client as that client can impersonate any user in the realm. +You might need this to bridge for applications where it is impossible to obtain a subject token to exchange. For example, +you may be integrating a legacy application that performs login directly with LDAP. In that case, the legacy app +is able to authenticate users itself, but not able to obtain a token. + +WARNING: It is very risky to enable direct naked impersonation for a client. If the client's credentials are ever + stolen, that client can impersonate any user in the system. + +==== Granting Permission for the Exchange + +If the `audience` parameter is provided, then the calling client must have permission to exchange to the client. How +to set this up is discussed earlier in this chapter. + +Additionaly, the calling client must be granted permission to impersonate users. In the admin console, go to the +`Users` screen and click on the `Permissions` tab. + +.Users Permission +image:{project_images}/exchange-users-permission-unset.png[] + +Toggle the `Permissions Enabled` switch to true. + +.Identity Provier Permission +image:{project_images}/exchange-users-permission-set.png[] + +You should see a `impersonation` link on the page. Click that to start defining the permission. It will bring you +to this page. + +.Users Impersonation Permission Setup +image:{project_images}/exchange-users-permission-setup.png[] + +You'll have to define a policy for this permission. Click the `Authorization` link, go to the `Policies` tab and create +a `Client` Policy. + +.Client Policy Creation +image:{project_images}/exchange-users-client-policy.png[] + +Here you enter in the starting client, that is the authenticated client that is requesting a token exchange. After you +create this policy, go back to the users' `impersonation` permission and add the client policy you just +defined. + +.Apply Client Policy +image:{project_images}/exchange-users-apply-policy.png[] + +Your client now has permission to impersonate users. If you do not do this correctly, you will get a 403 Forbidden response if you +try to make this type of exchange. + +NOTE: Public clients are not allowed to do direct naked impersonations. + + +==== Making the Request + +To make the request, simply specify the `requested_subject` parameter. This must be the username or user id of +a valid user. You can also specify an `audience` parameter if you wish. + +[source,bash] +---- +curl -X POST \ + -d "client_id=starting-client" \ + -d "client_secret=geheim" \ + --data-urlencode "grant_type=urn:ietf:params:oauth:grant-type:token-exchange" \ + -d "requested_subject=wburke" \ + http://localhost:8080/auth/realms/myrealm/protocol/openid-connect/token +---- + + + + +