Seamless-backchannel authentication

Last updated: April 28, 2023

Introduction

The seamless-backchannel authentication allows a service to get a user token without the user going through the authentication process, i.e. not involving the user to get an access token carrying his/her credentials.
It must be used in very specific cases, usually when asking by mail a user to review a product they bought. If the user has to login manually they might not bother and might not give feedback.

Important

The seamless-backchannel flow is subject to strict governance and will not be granted without justification.

Description

The seamless-backchannel process has two major steps:

  • Get a temporary / exchangeable token for a user;
  • Exchange this token with a valid member access token, carrying the user credentials.
Two clients can be involved in this process.
The first step is a step of mass generation, it is best to make a call with many member-ids, and not one-by-one.

In this document we will call these two clients: Client A and Client B.


The way the two clients exchange the exchangeable token is not in the scope of this document. It's up to these clients to find a way to exchange this exchangeable token.

Tokens details

Temporary / exchangeable token

This token is a custom JWT containing the following:

  • The member-id of the user;
  • The client-id of the client which can exchange this token with a valid member access token;
  • The scopes of the futur member access token.
  • Other technical parameters.
The temporary token does not represent the user credentials, so it cannot be used to access member API.
It has a long expiration date (~6 months for now, but it can change).
The exchange of this token does not grant a refresh token nor an id token.

Member access token

Its a usual member access token. It lives 15mn then expires. It represents the credentials of the user.

How to implement ?

Step 1: Getting the temporary token (client A)


Prerequisites

  • You need an API key to reach the first service. The API key can be found in the details of your subscription plan to Login in Gravitee (APIm);
  • The client asking for a temporary token (client A) must have the scope token-generator:seamless-backchannel;
  • The client (client A) must be authenticated with a bearer token to request a temporary token. It must have the client-credential flow;
  • The client which will exchange the token (client B) must have the scope token-exchange:seamless-backchannel
How to get a client-credentials bearer token


Details of the call

POST /connect/token/generator/seamless-backchannel

Headers:
Name Description Required
Authorization 'Bearer ' + access token from the prerequisites. Yes
Content-type application/json Yes
x-api-key The API key you can find in your Login subscription plan in APIm (Gravitee). The API key is a uuid4. Yes

Parameters:
Parameter Description Required
client_id The client id of client B. Yes
scopes A list of scopes to set in the exchangeable token.
If specified, the auto-approved scopes of the client B must contains every scope of this parameter.
If not specified, all the auto-approved scopes of the client B are set in the exchangeable token.
No

Body:
Parameter Description Required
data An array of member-ids. The number of member-ids must be between 1 and 10000. Yes


Example of a successful call:

curl --request POST --location 'https://api-eu.preprod.decathlon.net/connect/token/generator/seamless-backchannel?client_id=CLIENT_ID&scopes=SCOPES' \
--header 'Authorization: Bearer TOKEN' \
--header 'Content-Type: application/json' \
--header 'x-api-key: API_KEY' \
--data DATA
                                                
                                            

Example of a successful call with values:

curl --request POST --location 'https://api-eu.preprod.decathlon.net/connect/token/generator/seamless-backchannel?client_id=dkconnect&scopes=sports%2Ccontacts%2Cphone' \
--header 'Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzY29wZSI6WyJpZGVudGl0eTpzZWVrIiwibGVnYWwtZW50aXR5IiwiaWRlbnRpdHk6c2VuZGNvZGUiLCJpZGVudGl0eTp3cml0ZSIsInRva2VuLWV4Y2hhbmdlOnNlYW1sZXNzLWJhY2tjaGFubmVsIiwidG9rZW4tZXhjaGFuZ2UiLCJpZGVudGl0eSIsImlkZW50aXR5OnNlYXJjaCIsImVtYWlsIiwiaWRlbnRpdHk6Y3JlYXRlIiwiZW1haWw6d3JpdGUiLCJzcG9ydHMiLCJvcGVuaWQiLCJpZGVudGlmaWVycyIsInByb2ZpbGUiLCJpZGVudGl0eTpzaWduaW4iLCJ0b2tlbi1nZW5lcmF0b3I6c2VhbWxlc3MtYmFja2NoYW5uZWwiLCJwcm9maWxlOndyaXRlIiwiaWRlbnRpdHk6dmFsaWRhdGUiLCJhY2NvdW50OnBhc3N3b3JkIiwicGhvbmUiLCJwZXJzb24iLCJzcG9ydHM6d3JpdGUiLCJjb250YWN0cyIsImNvbnRhY3RzOndyaXRlIiwiaWRlbnRpdHk6bG9naW4iXSwiaXNzIjoiaHR0cDovL2xvY2FsaG9zdDo5OTk5IiwiZXhwIjoxNjc2NDUwNzgyLCJpYXQiOjE2NzY0NDk4ODIsImp0aSI6ImtMb1M3YWxZVExZaERXNW4ybnVqV3RVenY3SSIsImNsaWVudF9pZCI6ImRrY29ubmVjdCJ9.UxZsIIxHk7tXCFWYGA8DlhdtIwl_hIiGRMGi1Yb4-zoVRII4CrEDAY0kmnoEQ_RW-_7TMc5EZqPm7sESgEhmR2cv4AskeRuvTIrlv6vPf5d_JdPRpDjRQfYNg2ui5swuTeipLuS6qkx3o3VBmcOF77ELI2KZoHw24_Rfqva6PlMsBuEWHF1lebmOGyLpUlmFpENjgqZykvHNtC9xt6tn2f2_T9TmfqW14alpeHL6CQp14Agyldh1I-LQpGEq3K6eF91KoJjSrIdP37lDQOPBFfTtaz09SksqJlXRQGcSuBwVtxzuqdtvZuvTMAX3IuIMciOxntrL0Yo40ieigG0U6w' \
--header 'Content-Type: application/json' \
--header 'x-api-key: 3e91a0af-0029-4a9b-b2f8-05713e997fdb' \
--data '[
"7233cd9b-6557-4edb-8f3b-a6ff08a60402",
"dfa16f9e-7d9b-4243-acd5-7d64b9a1add3"
]'
                                                
                                            

In response you will get a JSON object who is a map of member-id: exchangeable token


{
"7233cd9b-6557-4edb-8f3b-a6ff08a60402": "eyJraWQiOiJtYWluIiwidHlwIjoiSldUIiwiYWxnIjoiUlMyNTYifQ.eyJzdWIiOiI3MjMzY2Q5Yi02NTU3LTRlZGItOGYzYi1hNmZmMDhhNjA0MDIiLCJzY29wZSI6WyJzcG9ydHMiLCJjb250YWN0cyIsInBob25lIl0sImlzcyI6Imh0dHA6Ly9sb2NhbGhvc3Q6OTk5OSIsImV4cCI6MTY3NjQ4NTA3OCwiaWF0IjoxNjc2NDg0MTc4LCJqdGkiOiJjYzFlYzljNC1jNTM0LTQ0MWItOGM2OS0zYTJhNzg2ZTFjNTUiLCJjbGllbnRfaWQiOiJka2Nvbm5lY3QifQ.lxJc7_aKuFqZAidj5E2ryMjw2yv4hNWSjPB5G2M4xxk48-NNTbDisBzbnffol5I3D7FrpgtB8E-4Cp6twl698XqkCCsIP_ncAF_8c8lU3dZqEluHPwu57CwhRVeoYv7D0aNhD91HqqJZGgJmZifEMQAIbHFvahuKFzrfg5Dq3vvzg7yJWHbD82W7M1IitWyeOtKtZGsnPkBcAtUxM6UpTzvdmtx1EIuAZWI1EP9otYdEiVoqu0B8M2UNDEhuDYyNBfKlga4zN7bkyvCSClfMv1g3xnQdgtRNs_nGNrlYRei85fomtPZJrtVvqDyH6YCGdoWeT-48MYTX2vLCCfv94A",
"dfa16f9e-7d9b-4243-acd5-7d64b9a1add3": "eyJraWQiOiJtYWluIiwidHlwIjoiSldUIiwiYWxnIjoiUlMyNTYifQ.eyJzdWIiOiJkZmExNmY5ZS03ZDliLTQyNDMtYWNkNS03ZDY0YjlhMWFkZDMiLCJzY29wZSI6WyJzcG9ydHMiLCJjb250YWN0cyIsInBob25lIl0sImlzcyI6Imh0dHA6Ly9sb2NhbGhvc3Q6OTk5OSIsImV4cCI6MTY3NjQ4NTA3OCwiaWF0IjoxNjc2NDg0MTc4LCJqdGkiOiIzZTI0ZTcyYy04MDBlLTQxODEtOWUxYy03OTEyM2U5NDc1ZWYiLCJjbGllbnRfaWQiOiJka2Nvbm5lY3QifQ.VFuJTJo_gIlEX55kSz7Za-nZmXHT7knHUfiBA8mMDw8ywj9pgfHj99L9ayujEk9O70JUJgVJOUgwaGsSoZeM4zTr0VbXpJ02m6wzeSy6M8aGXXbIV75TwwT-BSsZokeauL6wyHu9S94YWFM3tpMNA7sPzmAYkzBdTuzmkeGZejf2KgxOMXgUJ5PsDSlGDXc7MsXo8TzSVyechNgABqxbzv0qhkLVeSyv16_rTNl58Qh5OOCnEWQwjZdV2bGO-IyvQS_a9an6BuCaZ3tu8ihdZnk-2Pcgkae-hYcvBUXfN1gaH_JOWY2rOo2QK4en96mjMbthJOkTBrYBnLS_p-CjCg"
}
                                                
                                            

Step 2: Exchange the exchangeable token (client B)


Prerequisites

  • To ask for an exchange of an exchangeable token, the client (client B) must be authenticated with a basic auth or a bearer token (for the bearer, the client must have the client-credentials flow);
  • The client asking to exchange the exchangeable token (client B) must have the scope token-exchange:seamless-backchannel. This condition is verified during step 1, but we do another check during the exchange.


Details of the call

POST /connect/token/exchange

Headers:
Name Description Required
Authorization Two choices:
  • 'Bearer ' + access token from a client credentials authentication;
  • 'Basic ' + CLIENT_ID:CLIENT_SECRET encoded as base64
Yes
Content-Type application/x-www-form-urlencoded Yes

Body:
Parameter Description Required
grant_type urn:ietf:params:oauth:grant-type:token-exchange Yes
exchange_type urn:decathlon:params:oauth:exchange-type:seamless-backchannel-exchange Yes
subject_token_type urn:ietf:params:oauth:token-type:jwt Yes
subject_token The exchangeable token obtained in step 1. Yes
requested_token_type urn:ietf:params:oauth:token-type:access_token Yes


Example of a successfull call with Basic auth:

curl --location --request POST 'http://LOGIN_DOMAIN/connect/token/exchange' \
--header 'Authorization: Basic BASE64_AUTH' --header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'subject_token_type=urn:ietf:params:oauth:token-type:jwt' \
--data-urlencode 'grant_type=urn:ietf:params:oauth:grant-type:token-exchange' \
--data-urlencode 'exchange_type=urn:decathlon:params:oauth:exchange-type:seamless-backchannel-exchange' \
--data-urlencode 'subject_token=SUBJECT_TOKEN' \
--data-urlencode 'requested_token_type=urn:ietf:params:oauth:token-type:access_token'
                                                    
                                                

Example of a successfull call with Basic auth and values:

curl --location --request POST 'https://api-global.preprod.decathlon.net/connect/token/exchange' \
--header 'Authorization: Basic Y2xpZW50OnNlY3JldA==' --header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'subject_token_type=urn:ietf:params:oauth:token-type:jwt' \
--data-urlencode 'grant_type=urn:ietf:params:oauth:grant-type:token-exchange' \
--data-urlencode 'exchange_type=urn:decathlon:params:oauth:exchange-type:seamless-backchannel-exchange' \
--data-urlencode 'subject_token=eyJraWQiOiJnZW5lcmF0b3IiLCJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJzdWIiOiI3MjMzY2Q5Yi02NTU3LTRlZGItOGYzYi1hNmZmMDhhNjA0MDIiLCJhdWQiOiJodHRwOi8vbG9jYWxob3N0OjgwODAvdG9rZW4vZXhjaGFuZ2UiLCJzY29wZSI6WyJzcG9ydHMiLCJjb250YWN0cyIsInBob25lIl0sImlzcyI6Imh0dHA6Ly9sb2NhbGhvc3Q6OTk5OSIsImV4cCI6MTY3NjkxMjczMiwiaWF0IjoxNjc2OTExODMyLCJqdGkiOiJmZGFlMjk4YS0wMWJjLTQ1ZTItYTUxYS02MTFiZmNmMTIzZTEiLCJjbGllbnRfaWQiOiJka2Nvbm5lY3QifQ.k_DQ4a5Dx-nqj0chjA1ouiYjGmBBwpHBFgBLGbYdbV8ma4xuU7YmcNnr3nQ448g2nJvr-VYchX7ZzM0ACMjVxSP3-LzWNF-MzxqV4nzoBnk-uW4T4mxETxXurco3BYlEYfllpNqk7xXxizLWQgMZupE6xFmAnOG7gbSVA4tGBDRuDNR1l19xVdBFwAxjXudhgPkvM7dbthrooQ_pxBEgObHoAw3aK2fY9k94hG5-ruk3Ngu303HUcPcH5cVAeqTXaZ-5cVpmA4gJjYNfdBMohswXpLMS_kZ51RDD6_yOIzk8u6mrglxYpFf6kXAVz1KCcjIgIcxi8p3U8QQyiQQF7Q' \
--data-urlencode 'requested_token_type=urn:ietf:params:oauth:token-type:access_token'
                                                    
                                                

Terms & Services