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.
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 01En Manage tenants, creamos un nuevo tenant con Create (por ahora solo existe el Default Directory de tipo Workforce). [Imagen 02]
Imagen 02Elegimos la configuración External, la que se usa para autenticar clientes, y le damos a Continue. [Imagen 03]
Imagen 03Le damos a Use Azure subscription para vincular el tenant a una suscripción de Azure. [Imagen 04]
Imagen 04En 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]
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]
Revisamos el resumen y le damos a Create. La creación puede tardar hasta 30 minutos. [Imagen 07]
Imagen 07Cuando 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]
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 09En Directories + subscriptions, buscamos el nuevo tenant Blurlink Demo en la pestaña All Directories y le damos a Switch. [Imagen 10]
Imagen 10Ya 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 113. 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 12Le 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]
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 14Junto 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]
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]
Repetimos lo mismo para Blurlinks.ReadWrite (leer y crear). Ya tenemos los dos scopes. [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]
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]
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]
Quedan los cuatro claims configurados en el access token. [Imagen 21]
Imagen 21En Manifest verificamos que requestedAccessTokenVersion sea 2, porque el backend espera tokens v2. Si tuviera otro valor, lo cambiamos a 2 y guardamos. [Imagen 22]
4. Registrar el frontend (SPA)
Volvemos a App registrations y le damos a New registration. [Imagen 23]
Imagen 23Le 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]
Copiamos el Application (client) ID, que el frontend usará para identificarse ante Entra, y luego entramos a Authentication (Preview). [Imagen 25]
Imagen 25En 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 26Entramos a Token configuration y le damos a Add optional claim. [Imagen 27]
Imagen 27Elegimos 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]
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]
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]
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 31En 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]
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 33Explicació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 345. 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 35Le 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]
El user flow aparece en la lista y entramos a él. [Imagen 37]
Imagen 37En Applications le damos a Add application. [Imagen 38]
Imagen 38Elegimos 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]
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 40Con 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 deblurlink-demo-spala URL de producción con la ruta, por ejemplohttps://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- El usuario elige iniciar sesión o registrarse.
- El frontend lo lleva a la página de Entra.
- 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.
- Entra revisa los datos y, si es un registro, crea la cuenta.
- Entra devuelve al usuario a
/redirectcon 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. - 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. - 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.
- Entra le entrega las llaves.
- 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. - 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.










































