Hola, amiguitos. Aprovechando mi tiempo de ciudadano desempleado, decidí, como buen programador, avanzar mi side project. Como necesitaba un servicio de autenticación, elegí Entra External ID, y se me ocurrió la genial idea de crear una demo que me sirviera de guía para mis futuros proyectos. ¿Por qué no? Suena bien, ¿verdad? Después de un par de semanas terminé la demo, y se me ocurrió otra "genial idea". ¿Y si documento la demo para mi yo del futuro? Claro, ¿por qué no? Otros cuantos días de mi vida perdidos. Cuando al fin terminé, ansioso por continuar mi proyecto, se me volvió a ocurrir otra brillante idea. ¿Y si comparto esta documentación? ¡Claro!, ¿por qué no? Tal vez con esto podría conseguir trabajo (spoiler… no pasará). Y después de varios días mejorando mi pequeña doc, henos aquí... Espero que les sirva, hijos de p#t@.

Nota: Los textos de esta guía fueron redactados y revisados con ayuda de la IA. ¿Ustedes creen que yo sé de reglas gramaticales? Y claro que también me ayudó a buscar documentación actualizada de Azure. ¿Quién todavía busca manualmente en Google? En fin, para seguir esta guía deben conocer los conceptos básicos de programación (JWT, scope, claim, etc.) y de Azure (Entra ID, suscripción, etc.).

En esta guía configuraremos paso a paso Microsoft Entra External ID, el servicio de Microsoft para que los usuarios de una aplicación puedan registrarse e iniciar sesión.

Como ejemplo usaremos Blurlink, un proyecto ficticio. Vamos a crear un tenant de tipo External, registrar el backend y el frontend en App registrations y configurar un user flow de registro e inicio de sesión.

Al final conectaremos un frontend en React y una API en NestJS, solo para ver el flujo completo funcionando. Nada de lo que configuraremos en Entra depende del lenguaje ni del framework, así que también sirve para proyectos con otras tecnologías. Entonces empecemos.

Tipos de tenant

Los tenants pueden ser de tipo Workforce (para empleados) o External (para clientes). Las cuentas de Azure traen por defecto un tenant de tipo Workforce llamado "Default Directory". Por eso empezaremos creando un nuevo tenant de tipo External.

Nota: Al tenant también se le llama directory, por eso en el portal veremos nombres como Default Directory o Directories + subscriptions.

1. Crear el tenant externo

En el portal de Azure buscamos Microsoft Entra ID y en Overview le damos a Manage tenants. [Imagen 01]

Imagen 01

Imagen 01

En Manage tenants, creamos un nuevo tenant con Create (por ahora solo existe el Default Directory de tipo Workforce). [Imagen 02]

Imagen 02

Imagen 02

Elegimos la configuración External, la que se usa para autenticar clientes, y le damos a Continue. [Imagen 03]

Imagen 03

Imagen 03

Le damos a Use Azure subscription para vincular el tenant a una suscripción de Azure. [Imagen 04]

Imagen 04

Imagen 04

En Basics, colocamos el nombre del tenant, el dominio blurlinkdemo.onmicrosoft.com y la región (ni el dominio ni la región se pueden cambiar después), y continuamos con Next: Add a subscription. [Imagen 05]

Imagen 05

Imagen 05

En Add a subscription, elegimos la suscripción y con Create new creamos un resource group nuevo (rg-blurlink-entraid-demo) en East US. Continuamos con Next: Review + create. [Imagen 06]

Imagen 06

Imagen 06

Revisamos el resumen y le damos a Create. La creación puede tardar hasta 30 minutos. [Imagen 07]

Imagen 07

Imagen 07

Cuando termina, Blurlink Demo aparece en Manage tenants con tipo External. Al hacer clic en su nombre se abre Tenant details, donde vemos su Tenant ID. Lo anotamos junto con el subdominio (blurlinkdemo, lo que va antes de .onmicrosoft.com), porque los vamos a usar en el frontend y en el backend. [Imagen 08]

Imagen 08

Imagen 08

Nota: External ID se cobra en la suscripción vinculada al tenant, según cuántos usuarios inician sesión cada mes. Los primeros 50.000 usuarios del mes son gratis, así que una demo como esta no tiene costo.

2. Cambiar al tenant nuevo

A partir de aquí trabajaremos en el Microsoft Entra admin center, que es el portal que usa la documentación de External ID. Todavía estamos en Default Directory, así que abrimos la configuración con el ícono del engranaje de arriba a la derecha. [Imagen 09]

Imagen 09

Imagen 09

En Directories + subscriptions, buscamos el nuevo tenant Blurlink Demo en la pestaña All Directories y le damos a Switch. [Imagen 10]

Imagen 10

Imagen 10

Ya estamos en nuestro nuevo tenant, Blurlink Demo. Su nombre debe aparecer arriba a la derecha, debajo de nuestro correo, y en la página de inicio. [Imagen 11]

Imagen 11

Imagen 11

3. Registrar la API (backend)

En el menú de la izquierda, dentro de Entra ID, entramos a App registrations y le damos a New registration. [Imagen 12]

Imagen 12

Imagen 12

Le ponemos de nombre blurlink-demo-api y elegimos Single tenant only. El Redirect URI lo dejamos vacío, porque la API no inicia sesión, solo valida los tokens que le llegan. Le damos a Register. [Imagen 13]

Imagen 13

Imagen 13

Copiamos el Application (client) ID. El backend lo usa para comprobar que el token es para esta API, y el frontend, para pedir ese token. Luego entramos a Expose an API. [Imagen 14]

Imagen 14

Imagen 14

Junto a Application ID URI le damos a Add. En el panel, el campo ya viene con el formato api://<clientId>, usando el client ID de la API. Si viene vacío o con otro valor, lo escribimos con ese formato. Guardamos con Save. Ese valor es el prefijo de los permisos (scopes) de la API. [Imagen 15]

Imagen 15

Imagen 15

Con Add a scope creamos el permiso Blurlinks.Read. En Who can consent elegimos Admins only, llenamos el nombre y la descripción que verá el administrador, dejamos State en Enabled y le damos a Add scope. [Imagen 16]

Imagen 16

Imagen 16

Repetimos lo mismo para Blurlinks.ReadWrite (leer y crear). Ya tenemos los dos scopes. [Imagen 17]

Imagen 17

Imagen 17

Nota: Entra arma cada access token con la configuración de la API a la que va dirigido. Por eso los claims del access token los configuraremos acá, en blurlink-demo-api.

En Token configuration le damos a Add optional claim, elegimos el tipo Access, marcamos idtyp y le damos a Add. Este claim indica si el token es de un usuario o solo de una aplicación. [Imagen 18]

Imagen 18

Imagen 18

Volvemos a Add optional claim con el tipo Access y marcamos email, family_name y given_name (también se pueden marcar junto con idtyp en el paso anterior). El access token no trae estos datos por defecto, y los necesitamos para el mensaje de bienvenida. Le damos a Add. [Imagen 19]

Imagen 19

Imagen 19

Estos claims necesitan los permisos email y profile de Microsoft Graph, por lo que puede aparecer un aviso. Marcamos la casilla para que los agregue y le damos a Add. [Imagen 20]

Imagen 20

Imagen 20

Quedan los cuatro claims configurados en el access token. [Imagen 21]

Imagen 21

Imagen 21

En Manifest verificamos que requestedAccessTokenVersion sea 2, porque el backend espera tokens v2. Si tuviera otro valor, lo cambiamos a 2 y guardamos. [Imagen 22]

Imagen 22

Imagen 22

4. Registrar el frontend (SPA)

Volvemos a App registrations y le damos a New registration. [Imagen 23]

Imagen 23

Imagen 23

Le ponemos de nombre blurlink-demo-spa y elegimos Single tenant only. En Redirect URI elegimos la plataforma Single-page application (SPA) y escribimos http://localhost:5173/redirect, con el puerto de Vite y la ruta exacta. Es la página del frontend a la que Entra nos devuelve al iniciar y al cerrar sesión. Le damos a Register. [Imagen 24]

Imagen 24

Imagen 24

Copiamos el Application (client) ID, que el frontend usará para identificarse ante Entra, y luego entramos a Authentication (Preview). [Imagen 25]

Imagen 25

Imagen 25

En Authentication (Preview) vamos a la pestaña Settings y dejamos sin marcar las dos casillas de implicit grant. El Front-channel logout URL también queda vacío, porque solo sirve para cerrar sesión en varias apps a la vez. [Imagen 26]

Imagen 26

Imagen 26

Entramos a Token configuration y le damos a Add optional claim. [Imagen 27]

Imagen 27

Imagen 27

Elegimos el tipo ID, marcamos login_hint y le damos a Add. Con este claim, al cerrar sesión Entra ya no nos pregunta de qué cuenta queremos salir, porque ya sabe cuál es. El claim queda en la lista con tipo ID. [Imagen 28]

Imagen 28

Imagen 28

En API permissions le damos a Add a permission. En el panel que se abre vamos a la pestaña APIs my organization uses y elegimos blurlink-demo-api. [Imagen 29]

Imagen 29

Imagen 29

Elegimos Delegated permissions (la app llama a la API en nombre del usuario que inició sesión). Marcamos Blurlinks.Read y Blurlinks.ReadWrite, que son los scopes que creamos en la API, y le damos a Add permissions. [Imagen 30]

Imagen 30

Imagen 30

Volvemos a darle a Add a permission, pero esta vez nos quedamos en la pestaña Microsoft APIs y elegimos Microsoft Graph. [Imagen 31]

Imagen 31

Imagen 31

En Delegated permissions marcamos openid (iniciar sesión) y offline_access (renovar la sesión sin volver a pedir el login), y le damos a Add permissions. [Imagen 32]

Imagen 32

Imagen 32

Le damos a Grant admin consent for Blurlink Demo y confirmamos con Yes. En un tenant External los usuarios no pueden aceptar los permisos que pide el frontend, así que el admin los acepta por todos. Sin este paso, Entra no le da el token al frontend. [Imagen 33]

Imagen 33

Imagen 33

Explicación: El frontend pide el token a Entra enviándole el scope Blurlinks.Read. Entra necesita que el usuario haya dado su consentimiento para que el frontend tenga ese permiso (scope), pero como el usuario no puede darlo, el admin ya lo aceptó antes por todos los usuarios. Entra verifica eso y le entrega el token al frontend.

Con Refresh, todos los permisos quedan en estado Granted. [Imagen 34]

Imagen 34

Imagen 34

5. Crear el user flow

El user flow define la página de registro e inicio de sesión. Ahí se elige con qué se entra y qué datos se le piden al usuario. En el menú de la izquierda entramos a External Identities, abrimos User flows y le damos a New user flow. [Imagen 35]

Imagen 35

Imagen 35

Le ponemos de nombre SignUpSignIn, que no se puede cambiar después. En Identity providers elegimos Email with password; la otra opción, Email one-time passcode, manda un código al correo en vez de usar contraseña. En User attributes marcamos Given Name, Surname y Display Name; Email Address ya viene incluido. Le damos a Create. [Imagen 36]

Imagen 36

Imagen 36

El user flow aparece en la lista y entramos a él. [Imagen 37]

Imagen 37

Imagen 37

En Applications le damos a Add application. [Imagen 38]

Imagen 38

Imagen 38

Elegimos blurlink-demo-spa (nuestro frontend) y le damos a Select. Solo agregamos el SPA, porque es el que muestra el login; la API solo valida tokens. [Imagen 39]

Imagen 39

Imagen 39

El SPA queda asociado al user flow; sin esto, el login da error. Aquí también vemos el Application (client) ID del SPA, el mismo que anotamos antes. [Imagen 40]

Imagen 40

Imagen 40

Con esto terminamos la configuración en el portal. Ahora haremos un resumen de los datos importantes de la configuración, que necesitaremos para conectar el frontend, el backend y Entra.

TENANT (EXTERNAL) name: Blurlink Demo subdomain: blurlinkdemo tenantId: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxff6e BACKEND (API) name: blurlink-demo-api clientId: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxx708b scope: Blurlinks.Read FRONTEND (SPA) name: blurlink-demo-spa clientId: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxx88ce redirectUri: http://localhost:5173/redirect 

6. Repositorios del frontend y del backend

Esta guía se centra en la configuración de Entra External ID, por lo que no entraremos en los detalles del código. Esta sección solo nos permitirá terminar el flujo y comprobar que la configuración realizada funciona.

El frontend se construyó en React con MSAL, la librería de Microsoft que nos permitirá conectarnos a Entra. Con el client ID de blurlink-demo-spa, el subdominio y el tenant ID podremos registrarnos e iniciar sesión en la página de Entra que configuramos en el user flow, y con el scope Blurlinks.Read de blurlink-demo-api obtendremos el token para el backend. Gracias a la ruta /redirect que registramos, Entra nos devolverá a nuestra web.

El backend, construido en NestJS, solo recibirá el access token que le mande el frontend y lo validará con el subdominio, el tenant ID y el client ID de la API (blurlink-demo-api). Si el token es válido, responderá a las consultas HTTP siempre que el token traiga el permiso que pide cada endpoint, como Blurlinks.Read en GET /me.

Frontend: https://github.com/basiliok/demo-fe-entra-external-id-blurlink

Backend: https://github.com/basiliok/demo-be-entra-external-id-blurlink

Nota: En cada repositorio se explica cómo levantar el proyecto en su README.md.

Este video muestra la configuración funcionando. Nos registramos, la app nos da la bienvenida, cerramos sesión y al final el nuevo usuario aparece en nuestro tenant.

Nota: No hace falta desplegar el frontend ni el backend para probar la configuración de Entra External ID, porque Entra nunca llama a nuestras aplicaciones. Todo el flujo pasa por el navegador, así que el redirect URI solo tiene que estar registrado, no tiene que ser accesible desde internet (por eso sirve http://localhost). Si desplegamos, solo debemos agregar a los redirect URIs de blurlink-demo-spa la URL de producción con la ruta, por ejemplo https://tu-dominio.com/redirect.

7. Cómo funciona el flujo

Este diagrama muestra cómo trabajan juntos el usuario, el frontend, Entra y el backend, desde el registro o el inicio de sesión hasta el mensaje de bienvenida. Y no lo dibujó la IA, tuve que hacerlo yo. ¿Saben cuánto me tomó? ¿Lo saben? Mátenme.

Imagen 41

Imagen 41
  1. El usuario elige iniciar sesión o registrarse.
  2. El frontend lo lleva a la página de Entra.
  3. El usuario escribe su email y su contraseña. Si se registra, también su nombre, su apellido y el código que le llega para verificar su correo.
  4. Entra revisa los datos y, si es un registro, crea la cuenta.
  5. Entra devuelve al usuario a /redirect con un código. El frontend lo lleva a / y ahí le pide a Entra los tokens del inicio de sesión a cambio de ese código.
  6. Esos tokens no sirven para llamar al backend. Por eso, sin que el usuario lo note, el frontend le pide a Entra otro token, solo para el backend, y lo manda junto con GET /me.
  7. Si el backend aún no tiene las llaves públicas de Entra, o las pidió hace más de 10 minutos, se las pide.
  8. Entra le entrega las llaves.
  9. Con esas llaves, el backend comprueba que el token esté firmado por Entra, que lo haya emitido nuestro tenant, que sea para esta API, que no haya vencido y que traiga el permiso Blurlinks.Read.
  10. El backend devuelve los datos del usuario, y el frontend los muestra junto con un mensaje de bienvenida.

Ohhh, se acabó, qué pena. En serio, espero que les sirva. Me hubiera encantado continuar configurando el inicio de sesión con una cuenta de Google (que desde este punto es fácil), pero si no empiezo a buscar trabajo pronto, terminaré haciendo landing pages en WordPress. Hasta la próxima, amiguitos. 👋

PD: La introducción fue solo una broma.