Ajouter la connexion à une application avec Cognito

AWSBeginner
Pratiquer maintenant

Introduction

Une application de commandes doit permettre à ses utilisateurs de se connecter. Vous créerez un annuaire d'utilisateurs et un client d'application public, connecterez un utilisateur fictif, validerez les jetons émis et renouvellerez la session avant le nettoyage.

Terminez d'abord Construire et valider une API de commandes. Cet environnement neuf fournit son propre backend public, des données de connexion jetables et un exemple de validation des jetons. Gardez les fichiers de mots de passe et de jetons privés.

Lien avec les certifications

Certification Tâche de l’examen Pratique
Solutions Architect – Associate (SAA-C03) Tâche 1.2 Connexion Cognito, validation des jetons et renouvellement de session.
Developer – Associate (DVA-C02) Tâche 2.1 Connexion Cognito, validation des jetons et renouvellement de session.
Security – Specialty (SCS-C03) Tâche 4.1 Pratique des fondamentaux : Connexion Cognito, validation des jetons et renouvellement de session.

Vue d’ensemble du laboratoire

Schéma conceptuel : le client de connexion utilise un groupe d’utilisateurs Cognito et un client d’application public pour obtenir, valider et renouveler les jetons de session ; la connexion ne protège pas l’API de santé publique indépendante.

Créer l'annuaire des utilisateurs de l'application

Dans cette étape, vous créerez un groupe d'utilisateurs, un client d'application public et un utilisateur fictif confirmé.

Entrez dans l'espace de travail et utilisez umask 077 pour que les nouveaux fichiers soient accessibles uniquement à votre utilisateur. Cette commande agit sur les permissions des fichiers, pas sur les règles d'autorisation de l'API :

cd /home/labex/project
umask 077

Un groupe d'utilisateurs Cognito, ou user pool, est l'annuaire des utilisateurs de votre application. Ses utilisateurs se connectent à l'application ; votre identité IAM préparée pour la CLI administre les ressources cloud. Observez AWS View en haut pour comparer ces ressources natives.

Créez votre groupe d'utilisateurs. $(...) stocke l'identifiant renvoyé pour les commandes natives suivantes :

POOL_ID=$(aws cognito-idp create-user-pool \
  --pool-name labex-a04-users \
  --query UserPool.Id \
  --output text)
echo "$POOL_ID"

Enregistrez cet identifiant ; > écrit la valeur dans le fichier d'inventaire :

printf '%s\n' "$POOL_ID" > pool-id.txt

Un client d'application, ou app client, identifie l'application qui connecte les utilisateurs via ce groupe. Une application publique ne peut pas garder un secret client confidentiel. Créez ce client sans secret, en autorisant le flux nom d'utilisateur/mot de passe et le flux de renouvellement des jetons utilisés dans ce tutoriel :

CLIENT_ID=$(aws cognito-idp create-user-pool-client \
  --user-pool-id "$POOL_ID" \
  --client-name orders-client \
  --no-generate-secret \
  --explicit-auth-flows ALLOW_USER_PASSWORD_AUTH ALLOW_REFRESH_TOKEN_AUTH \
  --query UserPoolClient.ClientId \
  --output text)
echo "$CLIENT_ID"
printf '%s\n' "$CLIENT_ID" > client-id.txt

Inspectez la configuration du client sans demander de valeurs secrètes :

aws cognito-idp describe-user-pool-client \
  --user-pool-id "$POOL_ID" \
  --client-id "$CLIENT_ID" \
  --query '{Name:UserPoolClient.ClientName,Flows:UserPoolClient.ExplicitAuthFlows}'

Créez l'utilisateur de démonstration en désactivant l'envoi d'e-mail. Il s'agit d'une action de provisionnement par l'administrateur, distincte de la connexion ultérieure de l'utilisateur :

aws cognito-idp admin-create-user \
  --user-pool-id "$POOL_ID" \
  --username labex-demo \
  --message-action SUPPRESS \
  --user-attributes Name=email,Value=demo@example.test \
  --query '{Username:User.Username,Status:User.UserStatus}'

Le statut initial est FORCE_CHANGE_PASSWORD. Pour cet utilisateur de test jetable uniquement, appliquez le fichier fourni contenant un mot de passe permanent via la CLI. Ce fichier contient les champs Username, Password et Permanent ; la syntaxe file:// les lit sans afficher le mot de passe :

aws cognito-idp admin-set-user-password \
  --user-pool-id "$POOL_ID" \
  --cli-input-json file://demo-password.json

Inspectez uniquement le statut non secret de l'utilisateur :

aws cognito-idp admin-get-user \
  --user-pool-id "$POOL_ID" \
  --username labex-demo \
  --query '{Username:Username,Status:UserStatus,Enabled:Enabled}'

Vous devez obtenir labex-demo, CONFIRMED et true. Dans AWS View, comparez l'identifiant de votre groupe, orders-client, l'absence de secret client et l'utilisateur confirmé et activé. Exemple tiré de l'état réel du groupe, du client et de l'utilisateur natifs :

Groupe Cognito, client d'application public et utilisateur de démonstration confirmé

Le groupe indépendant labex-a04-reference reste vide. Aucun jeton utilisateur n'a encore été demandé.

Se connecter et lire l'identité de l'application

Dans cette étape, vous obtiendrez de vrais jetons pour l'utilisateur confirmé et observerez le rejet d'un mot de passe incorrect.

InitiateAuth avec USER_PASSWORD_AUTH authentifie le nom d'utilisateur et le mot de passe de l'application. Cette opération n'autorise pas l'utilisateur via l'identité IAM administrateur de votre CLI. Le fichier fourni sign-in.json contient les paramètres fictifs de connexion de cette démonstration.

Stockez uniquement AuthenticationResult dans un fichier privé. N'utilisez pas cat sur cette réponse : elle contient des jetons au porteur :

aws cognito-idp initiate-auth --client-id "$CLIENT_ID" --auth-flow USER_PASSWORD_AUTH --auth-parameters file://sign-in.json --query AuthenticationResult --output json > tokens.json

Affichez uniquement les champs non secrets de la réponse avec jq. L'expression de présence des jetons renvoie un booléen au lieu de leurs valeurs :

jq '{TokenType,ExpiresIn,TokensPresent:(has("AccessToken") and has("IdToken") and has("RefreshToken"))}' tokens.json

Vous devez obtenir Bearer, une durée d'expiration positive et TokensPresent: true. Le jeton d'accès autorise les requêtes utilisateur/API appropriées, le jeton d'identité transmet des informations d'identité à l'application et le jeton de renouvellement permet d'obtenir de nouveaux jetons d'accès et d'identité. Leurs rôles sont différents et ils ne sont pas interchangeables.

Extrayez les jetons d'accès et d'identité dans des fichiers privés destinés à leur transmission. jq -r écrit les chaînes brutes et la redirection évite leur affichage dans le terminal :

jq -r '.AccessToken' tokens.json > access-token.txt
jq -r '.IdToken' tokens.json > id-token.txt

GetUser s'authentifie avec le jeton d'accès. Demandez uniquement le nom d'utilisateur dans sa sortie :

aws cognito-idp get-user \
  --access-token "$(cat access-token.txt)" \
  --query Username \
  --output text

Vous devez obtenir labex-demo. Il s'agit d'une réponse Cognito réelle au jeton émis, et non d'une preuve déduite uniquement d'un fichier JSON local.

Essayez les paramètres fournis avec un mot de passe incorrect, en redirigeant toute réponse inattendue contenant des jetons vers un autre fichier privé :

aws cognito-idp initiate-auth --client-id "$CLIENT_ID" --auth-flow USER_PASSWORD_AUTH --auth-parameters file://wrong-sign-in.json --query AuthenticationResult --output json > rejected-login.json

Vous devez obtenir NotAuthorizedException: Incorrect username or password. La commande se termine volontairement avec un code non nul ; passez à l'étape suivante après avoir lu ce rejet précis. Une erreur de connexion ou de transport d'authentification ne prouve pas le rejet d'un mot de passe incorrect. N'écrasez pas vos jetons valides avec ce résultat échoué. La vérification automatisée de l'étape valide indépendamment les jetons émis et la réponse réelle de GetUser ; observez manuellement l'erreur précise de mot de passe incorrect.

Le client d'application et l'utilisateur confirmé appartiennent au même groupe ; une connexion réussie renvoie des jetons.

Valider les jetons signés et renouveler la session

Dans cette étape, vous vérifierez la signature et le destinataire prévu du jeton, renouvellerez la session et distinguerez la connexion de la protection des routes de l'API.

Un JWT contient un en-tête et des données de revendications encodés, ainsi qu'une signature. Le décoder ne suffit pas à prouver qui l'a émis. JWKS est l'ensemble des clés publiques de signature de l'émetteur ; RS256 utilise une signature RSA vérifiable avec ces clés publiques.

Lisez l'exemple fourni de validation dans une application ordinaire ; il ne contient aucun mot de passe ni jeton littéral :

cat verify_tokens.py

L'exemple récupère les clés JWKS publiques de votre groupe depuis le point de terminaison préparé dans cet espace de travail, vérifie RS256 et l'identifiant de clé, puis contrôle l'émetteur, l'heure actuelle, token_use et le client d'application. L'émetteur signé utilise l'identité du groupe Cognito. Le jeton d'accès identifie le client avec client_id ; le jeton d'identité utilise aud. Exécutez l'exemple avec le fichier de jetons enregistré et les identifiants réels du groupe et du client :

/home/labex/project/client-venv/bin/python verify_tokens.py tokens.json "$POOL_ID" "$CLIENT_ID"

Vous devez obtenir des résumés non secrets pour access et id, chacun avec RS256 et current_time_valid: true. L'exemple modifie aussi un octet de signature en mémoire et confirme son rejet avant d'accepter les revendications ; aucun jeton altéré n'est enregistré. La portée aws.cognito.signin.user.admin du jeton d'accès permet les opérations Cognito que l'utilisateur effectue pour lui-même. Cette portée ne constitue ni un accès administrateur AWS, ni une règle de propriété des commandes, ni une portée métier personnalisée.

Créez des paramètres privés de renouvellement à partir du jeton de renouvellement initial. Cette commande écrit dans un fichier sans exposer sa valeur :

jq '{REFRESH_TOKEN:.RefreshToken}' tokens.json > refresh-parameters.json

Obtenez de nouveaux jetons d'accès et d'identité sans renvoyer le mot de passe de l'utilisateur :

aws cognito-idp initiate-auth --client-id "$CLIENT_ID" --auth-flow REFRESH_TOKEN_AUTH --auth-parameters file://refresh-parameters.json --query AuthenticationResult --output json > refreshed.json

Validez les jetons renouvelés avec les mêmes contrôles de clés publiques et de revendications :

/home/labex/project/client-venv/bin/python verify_tokens.py refreshed.json "$POOL_ID" "$CLIENT_ID"

Vous devez obtenir des résumés valides des jetons d'accès et d'identité pour le même groupe et le même client. La réponse au renouvellement ne contient pas nécessairement un autre jeton de renouvellement ; conservez la réponse privée initiale jusqu'au nettoyage.

La connexion seule ne modifie pas l'API publique préparée. Trouvez son identifiant généré et envoyez une requête de santé publique sans jeton au porteur :

API_ID=$(aws apigatewayv2 get-apis \
  --query "Items[?Name=='labex-a04'].ApiId | [0]" \
  --output text)
echo "$API_ID"
printf '%s\n' "$API_ID" > api-id.txt
curl -i "http://127.0.0.1:8081/api/$API_ID/health"

Vous devez obtenir HTTP 200 et healthy: true. AWS View affiche toujours l'autorisation NONE pour toutes les routes et aucune commande. L'authentification de l'utilisateur a réussi, mais l'API n'exige pas encore de jeton. L'unité suivante ajoute l'autorisation JWT aux routes ; un jeton valide ne prouve toujours pas automatiquement la propriété d'une commande donnée.

Le renouvellement prolonge la session connectée pour le même client d’application. Il ne modifie pas l’autorisation des routes de l’API et n’accorde pas l’accès à une commande. Distinguez ces décisions en comparant les résumés d’identité renouvelés et la réponse de santé toujours publique.

Supprimer les ressources de connexion et d'API

Dans cette étape, vous supprimerez vos ressources de connexion et les ressources de démonstration du backend tout en conservant le groupe, la table et les journaux de référence indépendants.

Votre inventaire comprend labex-a04-users depuis pool-id.txt, orders-client depuis client-id.txt, l'utilisateur labex-demo, l'identifiant d'API dans api-id.txt, labex-a04-orders-api, son groupe de journaux de fonction, labex-a04-orders et la politique OrdersData du rôle. Supprimez uniquement ces ressources nommées.

Supprimez l'utilisateur fictif, puis le client d'application et votre groupe :

aws cognito-idp admin-delete-user --user-pool-id "$POOL_ID" --username labex-demo
aws cognito-idp delete-user-pool-client --user-pool-id "$POOL_ID" --client-id "$CLIENT_ID"
aws cognito-idp delete-user-pool --user-pool-id "$POOL_ID"

Supprimez l'API de travail préparée et les ressources de backend qui lui appartiennent :

aws apigatewayv2 delete-api --api-id "$API_ID"
aws lambda delete-function --function-name labex-a04-orders-api
aws logs delete-log-group --log-group-name /aws/lambda/labex-a04-orders-api
aws dynamodb delete-table \
  --table-name labex-a04-orders \
  --query TableDescription.TableName \
  --output text
aws iam delete-role-policy --role-name labex-a04-execution --policy-name OrdersData

Interrogez les inventaires natifs avec succès ; les erreurs de transport ne prouvent pas l'absence de ressources :

aws cognito-idp list-user-pools --max-results 60 --query 'UserPools[].Name'
aws apigatewayv2 get-apis --query 'Items[].Name'
aws lambda list-functions --query 'Functions[].FunctionName'
aws dynamodb list-tables --query TableNames

Vous devez retrouver uniquement le groupe et la table de référence, avec des listes d'API et de fonctions vides. AWS View doit afficher le même état et conserver l'élément de référence ainsi que INFO platform reference keep unchanged. Le rôle d'exécution préparé conserve FunctionLogs.

Supprimez vos fichiers d'authentification privés, y compris les fichiers fournis contenant les mots de passe fictifs. rm -f supprime uniquement les fichiers locaux explicitement listés :

rm -f tokens.json access-token.txt id-token.txt refreshed.json refresh-parameters.json rejected-login.json sign-in.json wrong-sign-in.json demo-password.json

La suppression des seuls fichiers locaux ne révoque pas une session côté serveur. Ici, l'utilisateur fictif, le client et le groupe ont aussi été supprimés ; ce laboratoire ne prétend pas fournir un mécanisme général de déconnexion ou de révocation JWT. Conservez les ressources de référence indépendantes jusqu'au nettoyage par l'auteur et à l'arrêt de la VM.

Résumé

Vous avez créé un annuaire d'utilisateurs d'application et un client public, provisionné un utilisateur fictif, établi une connexion et observé le rejet d'un mot de passe incorrect. Vous avez vérifié de vraies signatures RS256 et les revendications d'émetteur, de client, de temps et de type, lu l'identité réelle de l'utilisateur et renouvelé les jetons d'accès et d'identité. Vous avez distingué les utilisateurs Cognito des identités IAM et la connexion de l'autorisation de l'API, puis supprimé vos ressources et fichiers privés en conservant les références.

Pour approfondir ce sujet, consultez la documentation AWS : Rôles des jetons du groupe d’utilisateurs; Signatures JWT et validation des revendications; Actualisation de session et flux de jetons d’actualisation.