Appearance
Entra ID
Entra ID gestiona tanto usuarios y grupos como privilegios de acceso según roles. Es decir, proporciona un servicio IAM (Identity and Access Management) que incluye identidad, autenticación y autorización. Resulta especialmente robusto para entornos corporativos por su relación estrecha con el Active Directory (directorios heredados) y las cuentas de Microsoft 365. De hecho, si se compara con los servicios de AWS, necesitarías AWS IAM + Cognito para cubrir las mismas funciones.
Conceptos clave: Usuarios, Grupos y Roles...
Antes de empezar a administrar Entra ID (por ejemplo, con Azure CLI), es importante entender los aspectos principales:
Usuarios
- Representan personas (empleados, contratistas, socios, etc.) que se autentican
- Cada usuario tiene una identidad única (correo electrónico, nombre de usuario, etc.)
- Los usuarios pueden tener asignaciones de roles (permisos de acceso) y pertenecer a grupos
- Los tres tipos de usuarios que se gestionan son: usuarios, invitados y usuarios sincronizados (creados en el Active Directory)
Grupos
- Contenedores lógicos para agrupar usuarios (y a veces recursos)
- Simplifican la administración de permisos, de este modo, al asignar roles a un grupo afecta a todos sus miembros
- Ejemplos típicos: "Equipo de Marketing", "Desarrolladores", "Gerentes"
Roles
- La autorización se realiza mediante roles, los cuales se asignan a usuarios o grupos para otorgar acceso
- Estos definen permisos específicos (qué acciones un usuario puede realizar). Como principio se suelen asignar permisos mínimos
- Por ejemplo: "Administrador Global" (acceso completo), "Lector" (solo consultar), "Colaborador" (administrar recursos)
Permisos
- Los permisos son las acciones individuales permitidas (ej.
read,write,delete) - Entra ID permite un control granular: se pueden restringir permisos por recurso, aplicación o alcance
- Los permisos se heredan: un usuario en un grupo con un rol hereda automáticamente los permisos de ese rol
- Para ver los grupos (y, por tanto, los roles que heredan) de un usuario:
az ad user get-member-groups --id "correo-o-id-del-usuario"
Usando Azure CLI con Entra ID
La línea de comandos es una buena opción para administrar los servicios Azure. Basándonos en el sitio de documentación de Azure CLI, podemos instalarlo en Windows del modo acostumbrado (descargando y siguiendo el instalador).
Para MacOS se puede instalar ejecutando:
bash
brew install azure-cliDesde una terminal (o PowerShell en Windows) estaremos habilitados para ejecutar la primera sentencia de login, así:
bash
az loginEsto abre el navegador para ingresar tu usuario y al conectarse te preguntará el número de
tenant, por defecto1.
Personalmente me resulta más sencillo que con AWS
Una vez autenticado, los comandos az ad son la forma principal de interactuar con Entra ID. A continuación expongo algunos ejemplos básicos...
Listar usuarios
bash
az ad user list --filter "displayName eq 'Juan Pérez'"Crear un usuario básico
bash
az ad user create \
--user-principal-name [email protected] \
--display-name "Juan Pérez" \
--password 'Password123!' \
--force-change-password-next-login trueListar grupos
bash
az ad group listAsignar un usuario a un grupo
bash
az ad group member add \
--group "NombreDelGrupo" \
--member-id "id-del-usuario"Asignar un rol de directorio a un usuario
Los roles corporativos como Administrador Global son roles de directorio; az ad no tiene un comando propio para asignarlos, así que se invoca Microsoft Graph con az rest:
bash
# 1. Obtener el object id del usuario
USER_ID=$(az ad user show --id [email protected] --query id -o tsv)
# 2. Asignar el rol de directorio (roleDefinitionId de "Administrador Global")
az rest --method POST \
--url "https://graph.microsoft.com/v1.0/roleManagement/directory/roleAssignments" \
--body "{\"principalId\": \"$USER_ID\", \"roleDefinitionId\": \"62e90394-69f5-4237-9190-012177145e10\", \"directoryScopeId\": \"/\"}"Nota: El
roleDefinitionIdmostrado corresponde al rol Administrador Global. Los roles se asocian por defecto a todo el directorio (directoryScopeId: "/"). Para otros roles se puede consultar el catálogo conaz rest ... roleDefinitions. Son asignaciones de máximo privilegio: conviene usarlas con moderación y preferir PIM (Privileged Identity Management) para elevaciones temporales.
Nota: Los comandos
az adpermiten gestionar prácticamente cualquier aspecto de Entra ID: usuarios, grupos, aplicaciones, permisos y roles. Puedes ver la ayuda disponible conaz ad --helpoaz ad <comando> --help.
Ejemplo de OAuth 2.0 con PKCE
OAuth 2.0 con PKCE (Proof Key for Code Exchange) es el flujo recomendado para aplicaciones SPA y móviles. Añade una capa de seguridad adicional usando códigos verificadores.
1. Registrar la aplicación
bash
az ad app create \
--display-name "Mi App SPA" \
--spa-redirect-uris "http://localhost:3000"Anota el Application (client) ID que devuelve el comando: lo usarás como
client_iden los ejemplos siguientes. Para una SPA el redirect URI se registra bajo la plataforma Single-Page App con--spa-redirect-uris(y por seguridad debe serhttps, salvo al probar en local conhttp://localhost). Como la app usa PKCE (cliente público), no se genera client secret.
2. Flujo con PKCE (ejemplo en JavaScript)
javascript
// Generar un code_verifier aleatorio (43-128 caracteres)
const generateCodeVerifier = () => {
const array = new Uint8Array(32);
crypto.getRandomValues(array);
return btoa(String.fromCharCode(...array))
.replace(/\+/g, '-')
.replace(/\//g, '_')
.replace(/=/g, '');
};
// Generar un code_challenge a partir del verifier (S256)
const generateCodeChallenge = async (verifier) => {
const encoder = new TextEncoder();
const data = encoder.encode(verifier);
const digest = await crypto.subtle.digest('SHA-256', data);
return btoa(String.fromCharCode(...new Uint8Array(digest)))
.replace(/\+/g, '-')
.replace(/\//g, '_')
.replace(/=/g, '');
};
// Paso 1: Redirigir al usuario a autorizar
const authorize = async () => {
const codeVerifier = generateCodeVerifier();
const codeChallenge = await generateCodeChallenge(codeVerifier);
sessionStorage.setItem('code_verifier', codeVerifier);
const params = new URLSearchParams({
client_id: 'tu-client-id',
response_type: 'code',
redirect_uri: 'http://localhost:3000',
scope: 'openid profile email offline_access https://graph.microsoft.com/user.read',
state: 'random-state-value',
code_challenge: codeChallenge,
code_challenge_method: 'S256'
});
window.location.href =
`https://login.microsoftonline.com/tu-tenant-id/oauth2/v2.0/authorize?${params}`;
};
// Paso 2: Intercambiar el código por tokens
const callback = async () => {
const urlParams = new URLSearchParams(window.location.search);
const code = urlParams.get('code');
const codeVerifier = sessionStorage.getItem('code_verifier');
const response = await fetch(
'https://login.microsoftonline.com/tu-tenant-id/oauth2/v2.0/token',
{
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: new URLSearchParams({
client_id: 'tu-client-id',
grant_type: 'authorization_code',
code: code,
redirect_uri: 'http://localhost:3000',
code_verifier: codeVerifier
})
}
);
const { access_token, id_token, refresh_token } = await response.json();
console.log('Access Token:', access_token);
};3. Verbos curl equivalentes
bash
# Paso 1: Redirigir al navegador a autorizar
open "https://login.microsoftonline.com/{tenant-id}/oauth2/v2.0/authorize?\
client_id={client-id}\
&response_type=code\
&redirect_uri=http://localhost:3000\
&scope=openid%20profile%20email%20offline_access%20https://graph.microsoft.com/user.read\
&code_challenge={code-challenge}\
&code_challenge_method=S256"
# Paso 2: Intercambiar código por tokens
curl -X POST https://login.microsoftonline.com/{tenant-id}/oauth2/v2.0/token \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "client_id={client-id}" \
-d "grant_type=authorization_code" \
-d "code={authorization-code}" \
-d "redirect_uri=http://localhost:3000" \
-d "code_verifier={code-verifier}"Resumen del flujo PKCE:
- La app genera un
code_verifiery sucode_challenge(hash SHA-256)- Se redirige al usuario a autorizar
- Se devuelve un
codetemporal- La app intercambia
code+code_verifierporaccess_token- El servidor valida que el
code_verifiercoincida con elcode_challengeoriginal
Probar PKCE con GitHub (alternativa práctica)
Los ejemplos anteriores muestran el flujo sobre Entra ID, pero para probar los mismos conceptos sin depender de un tenant corporativo puedes usar GitHub OAuth Apps, que sigue el mismo authorization_code (aquí GitHub no exige PKCE porque el cliente usa client secret, pero el mecanismo del code es idéntico).
1. Crear una OAuth App en GitHub
Ve a Settings → Developer settings → OAuth Apps → New OAuth App y configura:
- Homepage URL:
http://localhost:3000 - Authorization callback URL:
http://localhost:3000/callback(GitHub sí requiere esta ruta) - Al crearla, copia el Client ID y el Client secret.
2. Redirigir al usuario a autorizar (curl)
bash
open "https://github.com/login/oauth/authorize?\
client_id={client-id}\
&scope=read:user\
&redirect_uri=http://localhost:3000/callback"El usuario autoriza y GitHub responde redirigiendo a tu app con ?code={authorization-code}&state=... en la URL.
3. Intercambiar el código por un token
bash
curl -X POST https://github.com/login/oauth/access_token \
-H "Accept: application/json" \
-d "client_id={client-id}" \
-d "client_secret={client-secret}" \
-d "code={authorization-code}" \
-d "redirect_uri=http://localhost:3000/callback"Nota: GitHub devuelve
{"access_token": "...", "token_type": "bearer"}en JSON. Eseaccess_tokenes el equivalente al de los ejemplos con Entra ID y puedes usarlo para llamar a la API de GitHub (curl -H "Authorization: Bearer {access_token}" https://api.github.com/user).