Connexion et tokens

Comment suivre ce chapitre

Entrées : clientEmail, clientPassword et le code de vérification reçu.

Étapes et résultat attendu : Le premier facteur demande la vérification ; le second retourne la session du client. Conservez les deux tokens après connexion ou renouvellement. La déconnexion termine la session actuelle.

Alternatives et actions ultérieures : Utilisez la connexion pour démarrer une session. Le renouvellement et la déconnexion sont des actions ultérieures de gestion de session.

Code source des DTO : AccessTokenOutputModel, AuthenticationSecondFactorOutputModel

Les variables affectées dans un bloc précédent sont réutilisées dans les suivants. Les saisies du client proviennent de votre interface. Conservez les identifiants et les valeurs de référence dans le contexte du client ; ne recréez pas ce contexte à chaque étape.

Les exemples utilisent des classes utilitaires communes. Consultez Classes utilitaires communes : code source C# et Java complet avant de copier un exemple.
Prérequis : clientEmail et clientPassword existants. Commencez avec un token GUEST et recueillez authenticationCode sur le canal du second facteur configuré.
À conserver pour la suite : userId et les valeurs actuelles accessToken, refreshToken et validUntil. Sauvegardez les deux nouveaux tokens après chaque renouvellement.
Ce chapitre décrit l’authentification à deux facteurs. Le résultat est un token portant le rôle de l’utilisateur (CLIENT, SELLER, ADMIN ou SUPERADMIN). Conservez AccessToken, RefreshToken, Id et ValidUntil. L’expiration et la période de renouvellement dépendent du service.

Authentification à deux facteurs

Entrées : E-mail et mot de passe du client, puis authenticationCode reçu.
Action : Effectuez les deux facteurs d’authentification.
À conserver / résultat attendu : Conservez userId, accessToken, refreshToken et validUntil de la réponse finale.
Utilisez un token GUEST dans Authorization. Après le premier facteur, recueillez le code sur le canal configuré pour le compte. Une configuration de test isolée peut aussi retourner ce code dans la réponse. Pour le compte client présenté, le second facteur retourne un token CLIENT pour les appels suivants.
								
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", guestToken);
// First factor authentication
var payload = JsonConvert.SerializeObject(new { AccountNumber = clientEmail, Password = clientPassword });
(await httpClient.PostAsync("api/v1/users/authentication/first-factor", new StringContent(payload, Encoding.UTF8, "application/json"))).EnsureSuccessStatusCode();
// Collect authenticationCode from the configured second-factor channel.
// Second factor authentication
payload = JsonConvert.SerializeObject(new { AccountNumber = clientEmail, Token = authenticationCode });
var httpResponseMessage = await httpClient.PostAsync("api/v1/users/authentication/second-factor", new StringContent(payload, Encoding.UTF8, "application/json"));
httpResponseMessage.EnsureSuccessStatusCode();
var resultAsString = await httpResponseMessage.Content.ReadAsStringAsync();
var authenticationResult = JsonConvert.DeserializeObject<AuthenticationSecondFactorOutputModel>(resultAsString);
// Now, set the CLIENT token for the next requests
var userId = authenticationResult.Id;
var accessToken = authenticationResult.AccessToken;
var refreshToken = authenticationResult.RefreshToken;
var validUntil = authenticationResult.ValidUntil;
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);

								
// First factor authentication
JsonObject firstFactorPayload = new JsonObject();
firstFactorPayload.addProperty("AccountNumber", clientEmail);
firstFactorPayload.addProperty("Password", clientPassword);

HttpRequest firstFactorRequest = HttpRequest.newBuilder()
    .timeout(Duration.ofMinutes(1))
    .uri(Settings.wmsUri("users/authentication/first-factor"))
    .header("Accept-Language", "de-DE")
    .header("Authorization", "Bearer " + Settings.GUEST_TOKEN)
    .header("Content-Type", "application/json")
    .POST(HttpRequest.BodyPublishers.ofString(firstFactorPayload.toString()))
    .build();

var firstFactorResponse = httpClient.send(firstFactorRequest, BodyHandlers.ofString());
Api.requireSuccess(firstFactorResponse);
// Collect authenticationCode from the configured second-factor channel.

// Second factor authentication
JsonObject secondFactorPayload = new JsonObject();
secondFactorPayload.addProperty("AccountNumber", clientEmail);
secondFactorPayload.addProperty("Token", authenticationCode);

HttpRequest secondFactorRequest = HttpRequest.newBuilder()
    .timeout(Duration.ofMinutes(1))
    .uri(Settings.wmsUri("users/authentication/second-factor"))
    .header("Accept-Language", "de-DE")
    .header("Authorization", "Bearer " + Settings.GUEST_TOKEN)
    .header("Content-Type", "application/json")
    .POST(HttpRequest.BodyPublishers.ofString(secondFactorPayload.toString()))
    .build();

var response = httpClient.send(secondFactorRequest, BodyHandlers.ofString());
Api.requireSuccess(response);
AuthenticationSecondFactorOutputModel authenticationResult = new Gson().fromJson(response.body(), AuthenticationSecondFactorOutputModel.class);

// Now, set the CLIENT token for the next requests
var userId = authenticationResult.Id;
var accessToken = authenticationResult.AccessToken;
var refreshToken = authenticationResult.RefreshToken;
var validUntil = authenticationResult.ValidUntil;

Le canal du second facteur est configuré pour le compte et l’environnement. Utilisez le code reçu par le client.

Se déconnecter

Entrées : Le token CLIENT actuel.
Action : Terminez la session actuelle.
À conserver / résultat attendu : Supprimez la session sauvegardée après déconnexion réussie.
Cette opération invalide le token d’authentification.
								
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);
(await httpClient.PostAsync("api/v1/users/authentication/logout", null)).EnsureSuccessStatusCode();

								
HttpRequest theRequest = HttpRequest.newBuilder()
    .timeout(Duration.ofMinutes(1))
    .uri(Settings.wmsUri("users/authentication/logout"))
    .header("Accept-Language", "de-DE")
    .header("Authorization", "Bearer " + accessToken)
    .header("Content-Type", "application/json")
    .POST(HttpRequest.BodyPublishers.noBody())
    .build();

var response = httpClient.send(theRequest, BodyHandlers.ofString());
Api.requireSuccess(response);

Un token invalidé par une déconnexion ne peut plus être renouvelé ; une nouvelle connexion est nécessaire.

Renouveler le token d’authentification

Entrées : userId et la paire actuelle Access-/Refresh-Token.
Action : Demandez une session renouvelée.
À conserver / résultat attendu : Remplacez les deux tokens sauvegardés et validUntil par les valeurs reçues.
À l’expiration du token, les demandes protégées retournent HTTP 401 ; le service peut inclure TOKEN-EXPIRED: true. Le renouvellement exige la paire actuelle et l’identifiant utilisateur. La durée autorisée est définie depuis la date de création sauvegardée du token ; ce n’est pas une fenêtre fixe de cinq minutes après expiration.
Autorisez la demande avec un token GUEST valide. Envoyez la paire actuelle dans le payload, puis remplacez les deux tokens sauvegardés par ceux reçus. En cas d’échec, reconnectez-vous ; ne répétez pas indéfiniment une demande avec une paire invalide.

httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", guestToken);
payload = JsonConvert.SerializeObject(new
{
    UserId = userId,
    RefreshToken = refreshToken,
    AccessToken = accessToken
});
httpResponseMessage = await httpClient.PostAsync("api/v1/users/authentication/access-token/refresh", new StringContent(payload, Encoding.UTF8, "application/json"));
httpResponseMessage.EnsureSuccessStatusCode();
resultAsString = await httpResponseMessage.Content.ReadAsStringAsync();
var accessTokenOutputModel = JsonConvert.DeserializeObject<AccessTokenOutputModel>(resultAsString);
// Set new CLIENT token for the next HTTP requests
accessToken = accessTokenOutputModel.AccessToken;
refreshToken = accessTokenOutputModel.RefreshToken;
validUntil = accessTokenOutputModel.ValidUntil;
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);

								
JsonObject thePayload = new JsonObject();
thePayload.addProperty("UserId", userId);
thePayload.addProperty("RefreshToken", refreshToken);
thePayload.addProperty("AccessToken", accessToken);

HttpRequest theRequest = HttpRequest.newBuilder()
    .timeout(Duration.ofMinutes(1))
    .uri(Settings.wmsUri("users/authentication/access-token/refresh"))
    .header("Accept-Language", "de-DE")
    .header("Authorization", "Bearer " + Settings.GUEST_TOKEN)
    .header("Content-Type", "application/json")
    .POST(HttpRequest.BodyPublishers.ofString(thePayload.toString()))
    .build();

var response = httpClient.send(theRequest, BodyHandlers.ofString());
Api.requireSuccess(response);
AccessTokenOutputModel accessTokenOutputModel = new Gson().fromJson(response.body(), AccessTokenOutputModel.class);

// New CLIENT token for the next HTTP requests
accessToken = accessTokenOutputModel.AccessToken;
refreshToken = accessTokenOutputModel.RefreshToken;
validUntil = accessTokenOutputModel.ValidUntil;

Reconnaître le résultat

Après le second facteur ou le renouvellement : remplacez la paire sauvegardée. Il s’agit d’un extrait de la réponse.

{"id":123,"accessToken":"<access-token>","refreshToken":"<refresh-token>","validUntil":"2026-10-13T12:00:00Z"}

Le catalogue des DTO contient les autres propriétés de la réponse. Traitez une demande échouée avant de poursuivre ; consultez Gestion des erreurs.