<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Basilio K</title>
    <description>The latest articles on DEV Community by Basilio K (@basiliok).</description>
    <link>https://dev.to/basiliok</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3053664%2F201fdb49-e4bc-4910-9082-1bd115085bb2.jpg</url>
      <title>DEV Community: Basilio K</title>
      <link>https://dev.to/basiliok</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/basiliok"/>
    <language>en</language>
    <item>
      <title>Cómo configurar Microsoft Entra External ID para el login de tu app web</title>
      <dc:creator>Basilio K</dc:creator>
      <pubDate>Wed, 11 Nov 2026 21:01:31 +0000</pubDate>
      <link>https://dev.to/basiliok/como-configurar-microsoft-entra-external-id-para-el-login-de-tu-app-web-idd</link>
      <guid>https://dev.to/basiliok/como-configurar-microsoft-entra-external-id-para-el-login-de-tu-app-web-idd</guid>
      <description>&lt;p&gt;Hola, amiguitos. Aprovechando mi tiempo de ciudadano desempleado, decidí, como buen programador, avanzar mi &lt;em&gt;side project&lt;/em&gt;. Como necesitaba un servicio de autenticación, elegí &lt;strong&gt;Entra External ID&lt;/strong&gt;, 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 &lt;em&gt;yo&lt;/em&gt; 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í. ¡Espera! Se me acaba de ocurrir otra genial idea. ¿Y si...? 🙃&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Nota:&lt;/strong&gt; 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.).&lt;/p&gt;
&lt;/blockquote&gt;

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

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

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

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fy8atdlul1odymyledze7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fy8atdlul1odymyledze7.png" alt="Tipos de tenant" width="769" height="373"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Los tenants pueden ser de tipo &lt;strong&gt;Workforce&lt;/strong&gt; (para empleados) o &lt;strong&gt;External&lt;/strong&gt; (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 &lt;strong&gt;External&lt;/strong&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Nota:&lt;/strong&gt; Al tenant también se le llama &lt;em&gt;directory&lt;/em&gt;, por eso en el portal veremos nombres como Default Directory o Directories + subscriptions.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  1. Crear el tenant externo
&lt;/h2&gt;

&lt;p&gt;En el portal de Azure buscamos &lt;strong&gt;Microsoft Entra ID&lt;/strong&gt; y en &lt;strong&gt;Overview&lt;/strong&gt; le damos a &lt;strong&gt;Manage tenants&lt;/strong&gt;. [Imagen 01]&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fb98hbhvcvtthc033dda3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fb98hbhvcvtthc033dda3.png" alt="Imagen 01" width="800" height="394"&gt;&lt;/a&gt;&lt;/p&gt;
Imagen 01



&lt;p&gt;En &lt;strong&gt;Manage tenants&lt;/strong&gt;, creamos un nuevo tenant con &lt;strong&gt;Create&lt;/strong&gt; (por ahora solo existe el Default Directory de tipo &lt;strong&gt;Workforce&lt;/strong&gt;). [Imagen 02]&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Foo0v20dl17eyge73u66p.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Foo0v20dl17eyge73u66p.png" alt="Imagen 02" width="799" height="274"&gt;&lt;/a&gt;&lt;/p&gt;
Imagen 02



&lt;p&gt;Elegimos la configuración &lt;strong&gt;External&lt;/strong&gt;, la que se usa para autenticar clientes, y le damos a &lt;strong&gt;Continue&lt;/strong&gt;. [Imagen 03]&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fzx0tn0mqhx1gz5hnwjtj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fzx0tn0mqhx1gz5hnwjtj.png" alt="Imagen 03" width="800" height="493"&gt;&lt;/a&gt;&lt;/p&gt;
Imagen 03



&lt;p&gt;Le damos a &lt;strong&gt;Use Azure subscription&lt;/strong&gt; para vincular el tenant a una suscripción de Azure. [Imagen 04]&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fk3wda5oxec209qbrgpra.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fk3wda5oxec209qbrgpra.png" alt="Imagen 04" width="800" height="452"&gt;&lt;/a&gt;&lt;/p&gt;
Imagen 04



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

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fua6w6lu361rz0arln3a4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fua6w6lu361rz0arln3a4.png" alt="Imagen 05" width="800" height="380"&gt;&lt;/a&gt;&lt;/p&gt;
Imagen 05



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

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F3x4ghp08woe7utjemi0t.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F3x4ghp08woe7utjemi0t.png" alt="Imagen 06" width="800" height="393"&gt;&lt;/a&gt;&lt;/p&gt;
Imagen 06



&lt;p&gt;Revisamos el resumen y le damos a &lt;strong&gt;Create&lt;/strong&gt;. La creación puede tardar hasta 30 minutos. [Imagen 07]&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F99xunx0vygud71ody9x7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F99xunx0vygud71ody9x7.png" alt="Imagen 07" width="799" height="568"&gt;&lt;/a&gt;&lt;/p&gt;
Imagen 07



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

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fk94i0zxfjs267gion21c.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fk94i0zxfjs267gion21c.png" alt="Imagen 08" width="800" height="438"&gt;&lt;/a&gt;&lt;/p&gt;
Imagen 08



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Nota:&lt;/strong&gt; 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.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  2. Cambiar al tenant nuevo
&lt;/h2&gt;

&lt;p&gt;A partir de aquí trabajaremos en el &lt;a href="https://entra.microsoft.com/" rel="noopener noreferrer"&gt;&lt;strong&gt;Microsoft Entra admin center&lt;/strong&gt;&lt;/a&gt;, que es el portal que usa la documentación de External ID. Todavía estamos en &lt;em&gt;Default Directory&lt;/em&gt;, así que abrimos la configuración con el ícono del engranaje de arriba a la derecha. [Imagen 09]&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fss2xu4aacjegdfkepm72.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fss2xu4aacjegdfkepm72.png" alt="Imagen 09" width="800" height="545"&gt;&lt;/a&gt;&lt;/p&gt;
Imagen 09



&lt;p&gt;En &lt;strong&gt;Directories + subscriptions&lt;/strong&gt;, buscamos el nuevo tenant &lt;strong&gt;Blurlink Demo&lt;/strong&gt; en la pestaña &lt;strong&gt;All Directories&lt;/strong&gt; y le damos a &lt;strong&gt;Switch&lt;/strong&gt;. [Imagen 10]&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Flm6xkha3oovlhmmtt5gk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Flm6xkha3oovlhmmtt5gk.png" alt="Imagen 10" width="800" height="472"&gt;&lt;/a&gt;&lt;/p&gt;
Imagen 10



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

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ftveco8ufirw64u1da1bf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ftveco8ufirw64u1da1bf.png" alt="Imagen 11" width="800" height="536"&gt;&lt;/a&gt;&lt;/p&gt;
Imagen 11



&lt;h2&gt;
  
  
  3. Registrar la API (backend)
&lt;/h2&gt;

&lt;p&gt;En el menú de la izquierda, dentro de &lt;strong&gt;Entra ID&lt;/strong&gt;, entramos a &lt;strong&gt;App registrations&lt;/strong&gt; y le damos a &lt;strong&gt;New registration&lt;/strong&gt;. [Imagen 12]&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fhm4qj612ojx1titfruft.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fhm4qj612ojx1titfruft.png" alt="Imagen 12" width="800" height="374"&gt;&lt;/a&gt;&lt;/p&gt;
Imagen 12



&lt;p&gt;Le ponemos de nombre &lt;code&gt;blurlink-demo-api&lt;/code&gt; 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 &lt;strong&gt;Register&lt;/strong&gt;. [Imagen 13]&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fzdns28zmukhit2i1o9ia.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fzdns28zmukhit2i1o9ia.png" alt="Imagen 13" width="800" height="444"&gt;&lt;/a&gt;&lt;/p&gt;
Imagen 13



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

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F0w3v2o81rcthnrdf9c01.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F0w3v2o81rcthnrdf9c01.png" alt="Imagen 14" width="800" height="442"&gt;&lt;/a&gt;&lt;/p&gt;
Imagen 14



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

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fhfpvfufnpapcubwhn6iu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fhfpvfufnpapcubwhn6iu.png" alt="Imagen 15" width="800" height="359"&gt;&lt;/a&gt;&lt;/p&gt;
Imagen 15



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

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F89997ubw8set91hqrsbx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F89997ubw8set91hqrsbx.png" alt="Imagen 16" width="800" height="452"&gt;&lt;/a&gt;&lt;/p&gt;
Imagen 16



&lt;p&gt;Repetimos lo mismo para &lt;code&gt;Blurlinks.ReadWrite&lt;/code&gt; (leer y crear). Ya tenemos los dos scopes. [Imagen 17]&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fz4ru5tlt6yb1slix99wd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fz4ru5tlt6yb1slix99wd.png" alt="Imagen 17" width="800" height="427"&gt;&lt;/a&gt;&lt;/p&gt;
Imagen 17



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Nota:&lt;/strong&gt; 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 &lt;code&gt;blurlink-demo-api&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

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

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fgeqvb2is899lhf0spyug.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fgeqvb2is899lhf0spyug.png" alt="Imagen 18" width="799" height="395"&gt;&lt;/a&gt;&lt;/p&gt;
Imagen 18



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

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fdqqjtp98fpyh1l028o30.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fdqqjtp98fpyh1l028o30.png" alt="Imagen 19" width="799" height="422"&gt;&lt;/a&gt;&lt;/p&gt;
Imagen 19



&lt;p&gt;Estos claims necesitan los permisos &lt;code&gt;email&lt;/code&gt; y &lt;code&gt;profile&lt;/code&gt; de &lt;em&gt;Microsoft Graph&lt;/em&gt;, por lo que puede aparecer un aviso. Marcamos la casilla para que los agregue y le damos a &lt;strong&gt;Add&lt;/strong&gt;. [Imagen 20]&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fv9d0ogsp085ciqpnn8t4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fv9d0ogsp085ciqpnn8t4.png" alt="Imagen 20" width="800" height="229"&gt;&lt;/a&gt;&lt;/p&gt;
Imagen 20



&lt;p&gt;Quedan los cuatro claims configurados en el access token. [Imagen 21]&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F99f72zof9cf5bv084sz4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F99f72zof9cf5bv084sz4.png" alt="Imagen 21" width="800" height="396"&gt;&lt;/a&gt;&lt;/p&gt;
Imagen 21



&lt;p&gt;En &lt;strong&gt;Manifest&lt;/strong&gt; verificamos que &lt;code&gt;requestedAccessTokenVersion&lt;/code&gt; sea 2, porque el backend espera tokens v2. Si tuviera otro valor, lo cambiamos a 2 y guardamos. [Imagen 22]&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ft5gk4iif3y1ap08ybjnj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ft5gk4iif3y1ap08ybjnj.png" alt="Imagen 22" width="799" height="435"&gt;&lt;/a&gt;&lt;/p&gt;
Imagen 22



&lt;h2&gt;
  
  
  4. Registrar el frontend (SPA)
&lt;/h2&gt;

&lt;p&gt;Volvemos a &lt;strong&gt;App registrations&lt;/strong&gt; y le damos a &lt;strong&gt;New registration&lt;/strong&gt;. [Imagen 23]&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fu1rys9mtc4fcg6jeghk4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fu1rys9mtc4fcg6jeghk4.png" alt="Imagen 23" width="800" height="414"&gt;&lt;/a&gt;&lt;/p&gt;
Imagen 23



&lt;p&gt;Le ponemos de nombre &lt;code&gt;blurlink-demo-spa&lt;/code&gt; y elegimos Single tenant only. En Redirect URI elegimos la plataforma Single-page application (SPA) y escribimos &lt;code&gt;http://localhost:5173/redirect&lt;/code&gt;, 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 &lt;strong&gt;Register&lt;/strong&gt;. [Imagen 24]&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fara1twlk4l0q8iv5joz4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fara1twlk4l0q8iv5joz4.png" alt="Imagen 24" width="800" height="538"&gt;&lt;/a&gt;&lt;/p&gt;
Imagen 24



&lt;p&gt;Copiamos el &lt;strong&gt;Application (client) ID&lt;/strong&gt;, que el frontend usará para identificarse ante Entra, y luego entramos a &lt;strong&gt;Authentication (Preview)&lt;/strong&gt;. [Imagen 25]&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F18acfkbzjcy9qs97a0di.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F18acfkbzjcy9qs97a0di.png" alt="Imagen 25" width="800" height="476"&gt;&lt;/a&gt;&lt;/p&gt;
Imagen 25



&lt;p&gt;En &lt;strong&gt;Authentication (Preview)&lt;/strong&gt; vamos a la pestaña &lt;strong&gt;Settings&lt;/strong&gt; 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]&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Frqg4lci0004vq0y04ett.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Frqg4lci0004vq0y04ett.png" alt="Imagen 26" width="800" height="524"&gt;&lt;/a&gt;&lt;/p&gt;
Imagen 26



&lt;p&gt;Entramos a &lt;strong&gt;Token configuration&lt;/strong&gt; y le damos a &lt;strong&gt;Add optional claim&lt;/strong&gt;. [Imagen 27]&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F7b9osbk1xhzuoceyx30a.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F7b9osbk1xhzuoceyx30a.png" alt="Imagen 27" width="800" height="506"&gt;&lt;/a&gt;&lt;/p&gt;
Imagen 27



&lt;p&gt;Elegimos el tipo &lt;em&gt;ID&lt;/em&gt;, marcamos &lt;code&gt;login_hint&lt;/code&gt; y le damos a &lt;strong&gt;Add&lt;/strong&gt;. 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]&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fnasydjloevmhnujjcvuz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fnasydjloevmhnujjcvuz.png" alt="Imagen 28" width="800" height="628"&gt;&lt;/a&gt;&lt;/p&gt;
Imagen 28



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

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fbxt3lhigmt6ig7rgr74d.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fbxt3lhigmt6ig7rgr74d.png" alt="Imagen 29" width="800" height="389"&gt;&lt;/a&gt;&lt;/p&gt;
Imagen 29



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

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fxnzqexe1ifo358gm5ala.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fxnzqexe1ifo358gm5ala.png" alt="Imagen 30" width="800" height="583"&gt;&lt;/a&gt;&lt;/p&gt;
Imagen 30



&lt;p&gt;Volvemos a darle a &lt;strong&gt;Add a permission&lt;/strong&gt;, pero esta vez nos quedamos en la pestaña &lt;strong&gt;Microsoft APIs&lt;/strong&gt; y elegimos &lt;strong&gt;Microsoft Graph&lt;/strong&gt;. [Imagen 31]&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ft7rnmxj5iboqe8vma0vm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ft7rnmxj5iboqe8vma0vm.png" alt="Imagen 31" width="800" height="394"&gt;&lt;/a&gt;&lt;/p&gt;
Imagen 31



&lt;p&gt;En &lt;strong&gt;Delegated permissions&lt;/strong&gt; marcamos &lt;code&gt;openid&lt;/code&gt; (iniciar sesión) y &lt;code&gt;offline_access&lt;/code&gt; (renovar la sesión sin volver a pedir el login), y le damos a &lt;strong&gt;Add permissions&lt;/strong&gt;. [Imagen 32]&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F1yydlu7swkpv4pabhajo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F1yydlu7swkpv4pabhajo.png" alt="Imagen 32" width="799" height="614"&gt;&lt;/a&gt;&lt;/p&gt;
Imagen 32



&lt;p&gt;Le damos a &lt;strong&gt;Grant admin consent for Blurlink Demo&lt;/strong&gt; y confirmamos con &lt;strong&gt;Yes&lt;/strong&gt;. 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]&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fnarki928636z6cjas6l1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fnarki928636z6cjas6l1.png" alt="Imagen 33" width="800" height="436"&gt;&lt;/a&gt;&lt;/p&gt;
Imagen 33



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Explicación:&lt;/strong&gt; El frontend pide el token a Entra enviándole el scope &lt;code&gt;Blurlinks.Read&lt;/code&gt;. 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.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Con &lt;strong&gt;Refresh&lt;/strong&gt;, todos los permisos quedan en estado Granted. [Imagen 34]&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fb1qksu7jgkv39ef4vpqm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fb1qksu7jgkv39ef4vpqm.png" alt="Imagen 34" width="800" height="427"&gt;&lt;/a&gt;&lt;/p&gt;
Imagen 34



&lt;h2&gt;
  
  
  5. Crear el user flow
&lt;/h2&gt;

&lt;p&gt;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 &lt;strong&gt;External Identities&lt;/strong&gt;, abrimos &lt;strong&gt;User flows&lt;/strong&gt; y le damos a &lt;strong&gt;New user flow&lt;/strong&gt;. [Imagen 35]&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fo0hfuusesdb8mxe6vyg8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fo0hfuusesdb8mxe6vyg8.png" alt="Imagen 35" width="800" height="551"&gt;&lt;/a&gt;&lt;/p&gt;
Imagen 35



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

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fqizebw18lucbtfegoldq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fqizebw18lucbtfegoldq.png" alt="Imagen 36" width="800" height="593"&gt;&lt;/a&gt;&lt;/p&gt;
Imagen 36



&lt;p&gt;El user flow aparece en la lista y entramos a él. [Imagen 37]&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fnz0etb04ux9c3s5sn3f1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fnz0etb04ux9c3s5sn3f1.png" alt="Imagen 37" width="800" height="521"&gt;&lt;/a&gt;&lt;/p&gt;
Imagen 37



&lt;p&gt;En &lt;strong&gt;Applications&lt;/strong&gt; le damos a &lt;strong&gt;Add application&lt;/strong&gt;. [Imagen 38]&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fmtglmmrld8pi7la12e6k.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fmtglmmrld8pi7la12e6k.png" alt="Imagen 38" width="799" height="480"&gt;&lt;/a&gt;&lt;/p&gt;
Imagen 38



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

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Frnqd7rb6ooe27nijizjo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Frnqd7rb6ooe27nijizjo.png" alt="Imagen 39" width="800" height="558"&gt;&lt;/a&gt;&lt;/p&gt;
Imagen 39



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

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fvwcv8jfph0yex1f1ptjt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fvwcv8jfph0yex1f1ptjt.png" alt="Imagen 40" width="800" height="471"&gt;&lt;/a&gt;&lt;/p&gt;
Imagen 40



&lt;p&gt;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.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;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
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  6. Repositorios del frontend y del backend
&lt;/h2&gt;

&lt;p&gt;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.&lt;/p&gt;

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

&lt;p&gt;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 (&lt;code&gt;blurlink-demo-api&lt;/code&gt;). Si el token es válido, responderá a las consultas HTTP siempre que el token traiga el permiso que pide cada endpoint, como &lt;code&gt;Blurlinks.Read&lt;/code&gt; en &lt;code&gt;GET /me&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Frontend: &lt;a href="https://github.com/basiliok/demo-fe-entra-external-id-blurlink" rel="noopener noreferrer"&gt;https://github.com/basiliok/demo-fe-entra-external-id-blurlink&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Backend: &lt;a href="https://github.com/basiliok/demo-be-entra-external-id-blurlink" rel="noopener noreferrer"&gt;https://github.com/basiliok/demo-be-entra-external-id-blurlink&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Nota:&lt;/strong&gt; En cada repositorio se explica cómo levantar el proyecto en su &lt;code&gt;README.md&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/YLqlKHvhSuQ" width="710" height="399"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Nota:&lt;/strong&gt; 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 &lt;code&gt;http://localhost&lt;/code&gt;). Si desplegamos, solo debemos agregar a los redirect URIs de &lt;code&gt;blurlink-demo-spa&lt;/code&gt; la URL de producción con la ruta, por ejemplo &lt;code&gt;https://tu-dominio.com/redirect&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  7. Cómo funciona el flujo
&lt;/h2&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fymwiyzr38owfqiv8jbdb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fymwiyzr38owfqiv8jbdb.png" alt="Imagen 41" width="799" height="470"&gt;&lt;/a&gt;&lt;/p&gt;
Imagen 41



&lt;ol&gt;
&lt;li&gt;El usuario elige iniciar sesión o registrarse.&lt;/li&gt;
&lt;li&gt;El frontend lo lleva a la página de Entra.&lt;/li&gt;
&lt;li&gt;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.&lt;/li&gt;
&lt;li&gt;Entra revisa los datos y, si es un registro, crea la cuenta.&lt;/li&gt;
&lt;li&gt;Entra devuelve al usuario a &lt;code&gt;/redirect&lt;/code&gt; con un código. El frontend lo lleva a &lt;code&gt;/&lt;/code&gt; y ahí le pide a Entra los tokens del inicio de sesión a cambio de ese código.&lt;/li&gt;
&lt;li&gt;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 &lt;code&gt;GET /me&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;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.&lt;/li&gt;
&lt;li&gt;Entra le entrega las llaves.&lt;/li&gt;
&lt;li&gt;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 &lt;code&gt;Blurlinks.Read&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;El backend devuelve los datos del usuario, y el frontend los muestra junto con un mensaje de bienvenida.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;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. 👋&lt;/p&gt;

</description>
      <category>azure</category>
      <category>authentication</category>
      <category>react</category>
      <category>nestjs</category>
    </item>
  </channel>
</rss>
