# ¿Quién sos, y qué te está permitido hacer?

Curso exprés sobre autenticación y autorización. 22 conceptos — authN y authZ, hash de contraseñas, MFA, passkeys, sesiones y JWT, OAuth 2.0 y OIDC, API keys, mínimo privilegio, RBAC, ABAC, chequeo de propiedad, IDOR y los otros fallos clásicos — cada uno con su nombre en inglés, un diagrama, una imagen y una ficha con un ejemplo. Al final, una hoja de referencia de una página con todos los conceptos.

- **Author:** Fedor Chishchin
- **Level:** intro
- **Reading time:** ~35 minutos de lectura
- **Published:** 2026-06-02
- **Source:** https://fedorthinks.com/es/learn/auth-express

---

## 1. Dos preguntas, una palabra

Detrás de la palabra «auth» se esconden dos preguntas distintas. La mayoría de los bugs de seguridad vienen de confundirlas — o de responder una y olvidar la otra.

### Authentication (authN) — ¿quién sos?

> Mostrar tu pasaporte en el aeropuerto — probar que realmente sos la persona que decís ser.

Este es el concepto de **Authentication (authN)**, y significa probar la identidad: un login, una passkey, un token que dice «esta realmente es Alice». Normalmente ocurre **una vez por sesión.** Si la errás, un impostor entra haciéndose pasar por otra persona. Pero probar quién sos no dice nada sobre qué te está permitido hacer — esa es la otra pregunta, completamente distinta.

_Diagram: La authN convierte una credencial (contraseña, passkey, token) en una identidad — y responde solo a la pregunta «¿quién es?»._

#### Authentication (authN) (probar la identidad)

- **Qué es:** Comprobar que el usuario es quien dice ser.
- **Cómo funciona:** El usuario presenta una credencial (contraseña, passkey, token); el sistema la verifica y establece una identidad.
- **Ejemplo:** Login con email y contraseña: «esta es Alice».
- **Trampa:** Saber quién es alguien no dice qué puede hacer.
- **Relaciones:** Alimenta a **Authorization**; se hace con **Password Hashing**, **MFA**, **Passkeys**, **OIDC**.

### Authorization (authZ) — ¿qué te está permitido hacer?

> Una tarjeta llave de hotel — no prueba nada sobre tu nombre, pero abre tu habitación y no las otras, y no la oficina del gerente.

Este es el concepto de **Authorization (authZ)**: decidir qué tiene permitido hacer una identidad — leer esto, editar aquello, nunca tocar el panel de admin. A diferencia de la authN, hay que verificarla **en cada request**, porque un solo usuario logueado puede tocar cien cosas distintas. **Saber quién es alguien no es permiso para hacer nada en particular.**

_Diagram: La authZ recibe quién, qué acción y qué recurso — y en cada request decide: permitir o denegar._

#### Authorization (authZ) (decidir permisos)

- **Qué es:** Decidir qué puede hacer esta identidad con este recurso.
- **Cómo funciona:** En cada request: quién + acción + recurso → regla → permitir o denegar.
- **Ejemplo:** Alice, la editora, puede editar el doc #42, pero no abrir el panel de admin.
- **Trampa:** Verificar una vez y olvidarse. Hay que verificar en **cada request**, del lado del servidor.
- **Relaciones:** Modelos — **Least Privilege**, **RBAC**, **ABAC**, **Ownership Check**; fallo — **Broken Access Control**.

### Dos capas — nunca las colapses

> Un club nocturno: el patovica revisa tu documento en la puerta una vez, y el barman igual revisa que tengas la edad cada vez que pedís un trago. Dos chequeos, dos momentos.

El error clásico es fusionar las dos — probar la identidad una vez y confiar en eso para siempre, o meter cada permiso dentro de un token de login y nunca volver a verificar. **La authN ocurre en la puerta; la authZ ocurre en cada puerta de adentro.** Mantenelas separadas, y verificá la segunda constantemente.

_Diagram: La authN es una puerta de entrada. La authZ es un chequeo en cada puerta interior — es decir, en cada request._

### Don't Roll Your Own Auth — nunca la armes por tu cuenta

> No soldás tu propia bóveda de banco con chapa en el garaje — comprás una construida y probada por gente que no hace otra cosa.

Esta es la práctica de **Don't Roll Your Own Auth**. La identidad es el cimiento sobre el que se apoya todo lo demás, y es tremendamente fácil equivocarse de forma sutil. **Usá estándares y librerías probadas** — protocolos establecidos, una librería o proveedor de auth curtido en batalla — no un esquema ingenioso que inventaste vos. La historia de la seguridad está llena de auth casera que parecía andar bien hasta que de golpe dejó de hacerlo.

#### Don't Roll Your Own Auth (estándares antes que hacerlo a mano)

- **Problema:** La auth casera parece andar bien hasta que alguien la rompe.
- **Idea:** Usar protocolos, librerías y proveedores probados.
- **Ejemplo:** En vez de tu propio esquema de tokens — OIDC y la auth de tu framework.
- **Coste:** Hay que aprender la herramienta de otro e integrarla bien.
- **Cuándo usarlo:** Casi siempre.
- **Relaciones:** Lleva a **Auth Provider**; estándares — **OAuth 2.0**, **OIDC**.

### El mapa: 22 conceptos en seis grupos

> Un llavero: primero ves todo el manojo, después aprendés qué llave abre qué puerta.

Los conceptos del curso se agrupan en seis grupos. Cada uno responde su propia pregunta: qué son las dos «auth», cómo probar la identidad, cómo seguir logueado, cómo dar acceso sin contraseña, cómo decidir permisos, y cómo suele romperse todo.

_Diagram: Seis grupos de conceptos — los capítulos 1–6 los siguen. El capítulo 7 es cómo elegir, más la hoja de referencia._

Cada concepto de abajo recibe el mismo tratamiento: su **nombre en inglés** (el término con el que vas a buscar en la documentación), una imagen de la vida real, un **diagrama** y una **ficha** con campos. Al final, una hoja de referencia con todos los conceptos.

> **Antes de cualquier decisión de auth:** "¿Se trata de probar quién es alguien — o de decidir qué puede hacer? No son la misma cerradura."

> La autenticación es la puerta. La autorización es cada puerta de adentro. Si te salteás la segunda, la primera no vale nada.

## 2. Probar quién sos

La autenticación se reduce a probar que sos vos. Los factores van desde la contraseña, débil pero universal, hasta la passkey moderna, resistente al phishing.

### Password Hashing — contraseñas, el default débil

> Una palabra secreta compartida con el portero — sirve hasta que alguien la escucha, la adivina, o la usás en todos lados.

Las contraseñas son universales y el factor común más débil: se reutilizan, se adivinan, se les hace phishing. Si hay que usarlas, la regla innegociable es **nunca guardarlas como texto**. Guardá un **hash** lento y con sal (Argon2, bcrypt) — eso es **Password Hashing** — para que una base de datos robada no entregue las contraseñas de todos. (Más sobre esto en el capítulo de errores.)

_Diagram: Contraseña + sal aleatoria → hash lento → solo se guarda el hash. Una base de datos robada no entrega ninguna contraseña._

#### Password Hashing (hash lento con sal)

- **Problema:** Contraseñas guardadas como texto: una filtración y el atacante las tiene todas.
- **Idea:** Guardar no la contraseña sino un hash lento con una **sal** — distinta para cada usuario.
- **Ejemplo:** Al hacer login, calcular Argon2/bcrypt de la contraseña tipeada y comparar.
- **Coste:** El login es un poco más lento — a propósito.
- **Cuándo usarlo:** Siempre, si guardás contraseñas.
- **Relaciones:** El anti-ejemplo es **Plaintext / Fast Hash**; sumá **MFA** encima.

### MFA — algo que sabés, tenés, sos

> Una caja de seguridad del banco necesita tu llave y la del banco. Una sola no abre nada.

**MFA (Multi-Factor Authentication)**, o doble factor, exige una segunda prueba además de la contraseña — **algo que tenés** (un código de una app, una llave de seguridad) o **algo que sos** (una huella digital). Así, ni una contraseña robada sirve por sí sola. Un código de app autenticadora (**TOTP**) es sólido; los códigos por SMS son débiles (se pueden interceptar) pero mejores que nada. **MFA es la mejora de seguridad más grande y barata que podés agregar.**

_Diagram: Tres tipos de factores: saber, tener, ser. Para entrar hacen falta al menos dos distintos._

#### MFA (Multi-Factor Authentication, 2FA)

- **Problema:** Una contraseña robada = acceso total a la cuenta.
- **Idea:** Exigir un segundo factor de otro tipo: «tener» o «ser».
- **Ejemplo:** Contraseña + un código TOTP de seis dígitos de una app autenticadora.
- **Coste:** Un paso extra al hacer login; los códigos por SMS se pueden interceptar.
- **Cuándo usarlo:** Donde importe; obligatorio en cuentas de admin.
- **Relaciones:** Refuerza **Password Hashing**; las **Passkeys** son el siguiente paso.

### Passkeys — el futuro sin contraseñas

> Una llave que solo funciona en la única puerta para la que fue cortada — falsificá el sitio, copiá la foto de la cerradura, y la llave simplemente no gira.

Las **passkeys** (basadas en el estándar **WebAuthn**) reemplazan las contraseñas por un par de claves criptográficas atado a tu dispositivo y al sitio real, así que no hay nada que phishear, reutilizar o filtrar — y Apple, Google y Microsoft ya las usan por defecto. La clave privada nunca sale de tu dispositivo; el sitio solo ve una firma. **Hacia ahí va la autenticación: nada que robar.**

_Diagram: El sitio manda un desafío, el dispositivo responde con una firma. Un sitio de phishing en otra dirección no recibe ninguna firma._

#### Passkeys (WebAuthn, login sin contraseña)

- **Problema:** A las contraseñas les hacen phishing, se reutilizan y se filtran.
- **Idea:** Un par de claves: la privada queda en el dispositivo, el sitio guarda la pública. Entrar es una firma.
- **Ejemplo:** Entrar con la huella o con Face ID en vez de tipear una contraseña.
- **Coste:** Necesita soporte del dispositivo y un camino de recuperación de respaldo.
- **Cuándo usarlo:** Como login principal donde los usuarios tengan dispositivos modernos.
- **Relaciones:** Reemplaza a **Password Hashing**; por sí sola, más fuerte que **MFA** por SMS.

> **La pregunta de la autenticación:** "Si este único factor fuera robado, ¿alguien podría entrar como el usuario — y cuál es mi segunda línea de defensa?"

> Una contraseña es un secreto que podés perder. Una passkey es una prueba que no. Sumá un segundo factor en cualquier caso.

## 3. Seguir logueado

HTTP te olvida entre un request y otro, así que después de entrar el sistema necesita una forma de seguir reconociéndote. Dos enfoques, con un compromiso real.

### Stateless HTTP — HTTP no tiene memoria

> Un negocio donde el empleado te olvida en cuanto te das vuelta — así que necesitás un ticket para demostrar, en tu próximo paso, que ya pagaste.

HTTP es **stateless** (sin estado): cada request es independiente; el servidor no recuerda que te logueaste hace un segundo. Entonces, después de la autenticación te dan algo — una cookie o un token — que mandás con cada request para decir «sigo siendo yo». Todo lo que sigue son dos formas de hacerlo. (Esto es la falta de estado del curso de protocolos.)

_Diagram: El servidor no recuerda ningún request anterior, así que cada request lleva consigo una cookie o un token._

#### Stateless HTTP (sin memoria entre requests)

- **Qué es:** El servidor no recuerda los requests anteriores del cliente.
- **Consecuencia:** Después del login necesitás un «pase» que viaje con cada request.
- **Ejemplo:** El navegador adjunta la cookie a cada request a ese sitio por sí solo.
- **Relaciones:** Dos respuestas — **Session** y **JWT**.

### Session — el servidor recuerda

> Un guardarropa — vos tenés un ticket numerado, y toda la información real está detrás del mostrador bajo ese número.

Con las **sesiones**, el servidor guarda quién sos y te da una cookie que contiene solo un **id de sesión** aleatorio. En cada request, busca el id. El servidor es la fuente de verdad, así que desloguear o bloquear a alguien es instantáneo — basta con borrar la sesión. El costo es que el servidor tiene que guardar y consultar ese estado. **El default correcto para la mayoría de las apps web.**

_Diagram: La cookie contiene solo un id. El servidor lo busca en el almacén de sesiones. Borrás la sesión — el usuario queda afuera al instante._

#### Session (sesión del lado del servidor)

- **Problema:** HTTP no recuerda quién sos entre un request y otro.
- **Idea:** El servidor guarda los datos del login; el cliente tiene solo un id de sesión aleatorio.
- **Ejemplo:** Cookie `sid=8f3a…` → en el almacén, `8f3a → Alice`.
- **Coste:** El servidor necesita un almacén y una consulta en cada request.
- **Cuándo usarlo:** Una app web normal. Este es el default.
- **Relaciones:** La alternativa es **JWT**; el id vive en una **httpOnly Cookie**; la revocación es instantánea.

### JWT — el token lleva la verdad

> Una pulsera de festival con tu nivel de acceso ya impreso y sellado contra manipulación — el guardia revisa el sello, no una lista de invitados.

Un **JWT (JSON Web Token)** es un token firmado que guarda el cliente y que _contiene_ la identidad y sus **claims**; el servidor solo verifica la firma, sin consultar nada. Eso lo hace stateless y fácil de escalar entre servicios — pero **difícil de revocar:** un token filtrado sigue siendo válido hasta que vence. Por eso se mantienen vidas cortas y se combina con un **refresh token**. **Excelente para APIs y microservicios; exagerado para una app web simple.**

_Diagram: JWT = header.payload.signature. La API verifica la firma sin base de datos. Un token filtrado vive hasta exp — de ahí las vidas cortas y el refresh token._

#### JWT (JSON Web Token)

- **Problema:** Muchos servicios, y hacer que cada uno consulte un almacén de sesiones compartido es caro.
- **Idea:** Poner la identidad y los permisos dentro del propio token y firmarlo.
- **Ejemplo:** Payload `sub: alice, role: editor, exp: …`; cada servicio verifica la firma por su cuenta.
- **Coste:** Difícil de revocar: un token filtrado es válido hasta que vence.
- **Cuándo usarlo:** APIs y microservicios — un JWT de vida corta + un **refresh token**.
- **Relaciones:** La alternativa a **Session**; la amenaza es **Token Leakage**.

### httpOnly Cookie — importa dónde lo guardás

> Una llave en un cajón con llave frente a una llave pegada con cinta en la puerta de entrada — la misma llave, una seguridad muy distinta.

Un token en el navegador debe ir en una **cookie httpOnly** (JavaScript no puede leerla), no en `localStorage`, donde cualquier script inyectado puede robarlo. El lugar donde se guarda es parte de la seguridad: si lo hacés mal, un solo bug de **XSS** le entrega todas las sesiones a un atacante. **Cómo transportás y guardás la credencial es tan importante como la credencial misma.**

_Diagram: Un script inyectado (XSS) puede leer localStorage, pero no puede leer una cookie httpOnly._

#### httpOnly Cookie (una cookie que JavaScript no puede leer)

- **Problema:** Un token en `localStorage` lo roba cualquier script inyectado.
- **Idea:** Guardar el token en una cookie con el flag `httpOnly` — JS no la ve.
- **Ejemplo:** `Set-Cookie: sid=…; HttpOnly`.
- **Coste:** Casi ninguno — es el default correcto en el navegador.
- **Relaciones:** Guarda un id de **Session** o un **JWT**; protege contra **Token Leakage**.

> **La pregunta de la sesión:** "¿Necesito revocación instantánea y simplicidad (sesiones) — o escala sin estado entre servicios (JWTs de vida corta)?"

> Sesiones: el servidor recuerda, y puede olvidarte al instante. JWT: el token recuerda, y no es fácil quitárselo.

## 4. Acceso delegado

Muchas veces no querés manejar la contraseña para nada — querés que los usuarios entren con una cuenta que ya tienen, o que un servicio actúe en nombre de otro. Para eso sirven OAuth2 y OIDC.

### OAuth 2.0 — dar acceso sin compartir la contraseña

> Una llave de valet que arranca el auto y abre la puerta, pero no el baúl ni la guantera — entregás acceso limitado, no todo tu llavero.

Este es el protocolo **OAuth 2.0**. Permite que un usuario le dé a tu app acceso limitado a su cuenta en otro servicio — tu app lee su Google Calendar — **sin darte nunca su contraseña de Google.** El otro servicio le entrega a tu app un **access token** limitado por un **scope** («leer el calendario, nada más»). Trata de _autorización_ delegada, no de identidad.

_Diagram: El usuario inicia sesión en Google y da su consentimiento. La app recibe un token de alcance acotado y llama a la API con él. Nunca ve la contraseña._

#### OAuth 2.0 (autorización delegada)

- **Problema:** Una app necesita acceso a la cuenta de alguien en otro lado, pero no puede tener la contraseña.
- **Idea:** El servicio dueño le emite a la app un **access token** con un **scope** acotado.
- **Ejemplo:** Tu app lee el Google Calendar del usuario — y solo eso.
- **Coste:** Un protocolo complejo; hacer el baile de tokens a mano es peligroso.
- **Cuándo usarlo:** Actuar en nombre de un usuario en otro servicio.
- **Relaciones:** No dice quién es el usuario — eso es **OIDC** encima.

### OIDC — OAuth2 que además dice quién sos

> La llave de valet, ahora con un documento con foto sujeto a ella — no solo «qué abre esta llave», sino «y acá está a quién pertenece».

OAuth2 por sí solo te dice a qué puede acceder una app, no _quién_ es el usuario. **OpenID Connect (OIDC)** agrega encima una capa fina de identidad — un **ID token** con claims verificados (esta es Alice, este es su email). Es lo que está detrás de «**Entrar con Google**» y del **single sign-on (SSO)**. Cuando querés login social o SSO, OIDC es el estándar.

_Diagram: OIDC es una capa fina sobre OAuth 2.0: junto al access token («qué se permite») viene un ID token («quién es»)._

#### OIDC (OpenID Connect)

- **Problema:** OAuth2 da acceso pero no dice quién es el usuario.
- **Idea:** Agregar un **ID token** con datos de identidad verificados.
- **Ejemplo:** El botón «Entrar con Google»; entrar a herramientas del trabajo con SSO.
- **Coste:** Dependés de un proveedor de identidad externo.
- **Cuándo usarlo:** Login social y single sign-on.
- **Relaciones:** Construido sobre **OAuth 2.0**; una forma de hacer **Authentication**.

### API Key — la credencial simple para máquinas

> Una llave de repuesto que le das a un contratista de confianza — sin nombre, solo «quien la tenga puede entrar».

Una **API key** es una cadena secreta larga que identifica a un programa, no a una persona — se usa para acceso entre servicios y programático. Simple y efectiva, pero _es_ la credencial: quien la encuentre, entra. Por eso se acota su alcance, se rota, y **nunca se sube a git ni se pone en una URL.** Sirve para máquinas; no reemplaza una identidad real de usuario.

_Diagram: El programa manda la clave en un header; la API verifica la clave y su alcance. Nunca en git, nunca en una URL, rotada con regularidad._

#### API Key (credencial de máquina)

- **Problema:** Un programa necesita entrar a una API sin humano y sin login.
- **Idea:** Un secreto largo que identifica al programa.
- **Ejemplo:** Un backend llama a una API de pagos con la clave en un header.
- **Coste:** La clave es el acceso: quien la encuentra, entra.
- **Cuándo usarlo:** De máquina a máquina. No para loguear personas.
- **Relaciones:** Acotala con **Least Privilege**; la amenaza principal es **Token Leakage**.

> **La pregunta de la delegación:** "¿Necesito actuar en nombre de un usuario en otro lado (OAuth2), saber quién es mediante un proveedor (OIDC), o solo identificar una máquina (API key)?"

> OAuth2 pide prestado el acceso sin la contraseña. OIDC suma «y acá está quién es». Usá el estándar — no inventes tu propio baile de tokens.

## 5. Qué tenés permitido hacer

Una vez que sabés quién es alguien, decidís qué puede tocar. Los modelos van desde roles gruesos hasta políticas finas — y la regla debajo de todos es denegar por defecto.

### Deny by Default / Least Privilege — prohibido salvo que se permita

> La credencial de un empleado nuevo que no abre nada hasta que se le concede cada puerta de forma explícita — en vez de abrirlo todo hasta que alguien se acuerde de cerrar unas pocas.

La base de la autorización son dos reglas. **Deny by default:** todo está prohibido salvo que se permita explícitamente. **Least privilege:** cada identidad recibe el acceso **mínimo** que necesita, no más. Los sistemas abiertos por defecto filtran — siempre alguien se olvida de restringir el nuevo endpoint. Los sistemas cerrados por defecto fallan de forma segura. **Empezá desde el «no» y concedé con intención.**

_Diagram: Un permiso explícito — dejalo pasar, y solo con el mínimo necesario. Sin permiso, o poco claro — denegar._

#### Least Privilege (denegar por defecto)

- **Problema:** Alguien se olvidó de cerrar el nuevo endpoint — y está abierto para todos.
- **Idea:** «No» por defecto; conceder solo el mínimo necesario.
- **Ejemplo:** Un empleado nuevo recibe acceso solo a su propio proyecto.
- **Coste:** Hay que conceder permisos explícitamente con más frecuencia.
- **Cuándo usarlo:** Siempre — es la base de todo modelo de permisos.
- **Relaciones:** El cimiento de **RBAC**, **ABAC**, **Ownership Check**.

### RBAC — permisos por rol

> Un teatro donde el tipo de entrada — platea, palco, pase de backstage — decide adónde podés ir, sin nombrarte a vos personalmente.

**RBAC (Role-Based Access Control)** agrupa permisos en roles — admin, editor, lector — y asigna usuarios a roles. Simple, legible y suficiente para la mayoría de las apps: «los editores pueden publicar, los lectores no». Se vuelve grueso cuando las reglas dependen del contexto o del registro concreto, y ahí entran los siguientes modelos.

_Diagram: Usuario → rol → conjunto de permisos. Los permisos van a los roles, no directamente a las personas._

#### RBAC (Role-Based Access Control)

- **Problema:** Dar permisos a cada persona por separado es un caos.
- **Idea:** Los permisos van a los roles; los roles van a los usuarios.
- **Ejemplo:** «Los editores pueden publicar; los lectores solo pueden leer».
- **Coste:** Grueso cuando una regla depende del contexto o del registro concreto.
- **Cuándo usarlo:** La mayoría de las apps.
- **Relaciones:** Más fino — **ABAC**; siempre sumá un **Ownership Check**.

### ABAC — permisos por política

> Una regla en vez de una lista — «los gerentes pueden aprobar gastos de menos de 10k, en horario laboral, desde un dispositivo de la empresa» — evaluada de nuevo cada vez.

**ABAC (Attribute-Based Access Control)** decide a partir de atributos del usuario, del recurso y del contexto — rol _y_ monto _y_ hora _y_ dispositivo. Mucho más flexible que los roles fijos, y mucho más complejo. La señal para adoptarlo: estás apilando más de un par de condiciones `if` a medida sobre tus chequeos de rol.

_Diagram: Los atributos del usuario, del recurso y del contexto entran en una política que decide de nuevo en cada request._

#### ABAC (Attribute-Based Access Control)

- **Problema:** Los permisos dependen no solo del rol sino del monto, la hora, el dispositivo.
- **Idea:** Una regla de política sobre atributos del usuario, del recurso y del contexto.
- **Ejemplo:** Un gerente aprueba un gasto de menos de 10k, en horario laboral, desde una laptop del trabajo.
- **Coste:** Mucho más difícil de escribir, leer y testear.
- **Cuándo usarlo:** Cuando a tus roles ya les pegaste más de un par de `if` a medida.
- **Relaciones:** Crece a partir de **RBAC**; se apoya en **Least Privilege**.

### Ownership Check — ¿podés tocar este registro?

> Tenés un carnet de biblioteca válido (un rol), pero eso no te deja leer las notas garabateadas en el libro que otro tiene prestado.

El **ownership check** (autorización a nivel de objeto) es el chequeo que más se olvida: incluso un «editor» válido solo debe editar **sus propios** documentos, no los de todos. El rol dice «los editores pueden editar»; igual tenés que verificar que este editor es dueño de _esta_ fila. Olvidarlo es el bug de control de acceso más común — cambiás el id en la URL y estás en los datos de otro. **Verificá siempre el objeto, no solo el rol.**

_Diagram: Dos chequeos: el rol («¿es editor?») y la propiedad («¿este doc es suyo?»). Permitir solo si pasan ambos._

#### Ownership Check (authZ a nivel de objeto)

- **Problema:** El rol permite «editar documentos» — y el usuario edita los de otros.
- **Idea:** Además del rol, verificar que este objeto le pertenece a este usuario.
- **Ejemplo:** Antes de `PUT /docs/42`, verificar que el dueño del doc 42 es el usuario actual.
- **Coste:** Un chequeo extra en cada acceso a un objeto.
- **Cuándo usarlo:** Siempre, cuando los datos tienen dueño.
- **Relaciones:** Complementa a **RBAC**/**ABAC**; sin él — **IDOR**.

> **La pregunta de los permisos:** "¿Verifiqué no solo el rol, sino que este usuario concreto tiene permitido tocar esta cosa concreta?"

> Denegá por defecto. Concedé lo mínimo. Y preguntá siempre no solo «qué rol» sino «de quién es el registro».

## 6. Cómo se rompe

La auth falla de un puñado de formas bien conocidas — las mismas, una y otra vez, app tras app. Conocerlas es la mitad de la defensa.

### Broken Access Control / IDOR — olvidarse de verificar

> Un edificio donde la puerta de entrada está vigilada pero todas las puertas internas están sin llave — una vez adentro, podés caminar a cualquier lado.

**Broken Access Control** es la vulnerabilidad web número uno: un endpoint autentica al usuario pero **se olvida de verificar que esté autorizado** para lo que pidió. Su forma más común es **IDOR (Insecure Direct Object Reference)** — cambiar `/orders/123` por `/orders/124` y ver el pedido de otra persona, porque el servidor nunca verificó la propiedad. Filtraciones de millones de registros se explican justo por esto. **Verificá la authZ en cada request, del lado del servidor, contra el objeto real.**

_Diagram: Bob entró honestamente, pero el servidor no verifica la propiedad — cambiás el id en la URL y ves el pedido de otro._

#### Broken Access Control / IDOR (falta de chequeo de permisos)

- **Qué es:** El usuario está autenticado, pero no se verifican sus derechos sobre el objeto.
- **Cómo se ve:** `/orders/123` → `/orders/124` — y aparece el pedido de otro.
- **Daño:** Filtraciones de millones de registros.
- **Arreglo:** authZ en cada request, del lado del servidor: `WHERE id = 124 AND owner = current_user`.
- **Relaciones:** Se cura con **Ownership Check** y **Least Privilege**.

### Plaintext / Fast Hash — guardar mal las contraseñas

> Guardar las llaves de repuesto de todas las casas de la calle en un frasco de vidrio en el porche.

Guardar contraseñas en **texto plano** — o con un hash rápido como **MD5** — significa que una sola filtración de la base expone a todos, y las contraseñas reutilizadas comprometen también las otras cuentas. Las contraseñas hay que **hashearlas de forma lenta e individual** (Argon2, bcrypt) para que sea caro crackearlas incluso si las roban. **Que el hash sea lento es el objetivo, no un defecto.**

_Diagram: Un hash rápido — intentos baratos, contraseñas crackeadas rápido. Un hash lento con sal — cada intento es caro._

#### Plaintext / Fast Hash (contraseñas en texto o MD5)

- **Qué es:** Contraseñas en la base de datos tal cual o bajo un hash rápido.
- **Daño:** Una filtración expone todas las contraseñas; las contraseñas reutilizadas abren también otras cuentas.
- **Arreglo:** Un hash lento con sal: Argon2 o bcrypt.
- **Relaciones:** La versión correcta es **Password Hashing**.

### Token Leakage — filtrar y confiar en tokens

> Escribir el código de la alarma en un papelito pegado en la puerta — la cerradura está bien; vos regalaste el secreto.

**Token leakage** es la forma en que escapan los tokens y las claves. Se filtran por **URLs (que se loguean), el `localStorage` del navegador (que un script puede leer) y secretos subidos a git.** Y un token hay que _verificarlo_, no confiar en él porque apareció — uno alterado o vencido debe rechazarse. Tratá toda credencial como algo que algún día se va a filtrar: vidas cortas, rotación, y nunca en un lugar que se loguee o se raspe.

_Diagram: Tres caminos clásicos de filtración: URLs en logs, localStorage y git. La defensa: el servidor verifica cada token, las vidas son cortas, las claves rotan._

#### Token Leakage (tokens y claves filtrados)

- **Qué es:** Una credencial termina en un lugar donde se puede leer o encontrar.
- **Cómo se ve:** `?token=` en una URL, un token en `localStorage`, una clave en un commit de git.
- **Daño:** Quien encuentre el token, entra.
- **Arreglo:** Verificar firma y vencimiento; vidas cortas, rotación; una **httpOnly Cookie** en el navegador.
- **Relaciones:** Duele más con **JWT** y **API Key**.

### Trusting the Client — creerle a lo que dice el navegador

> Un negocio que deja que los clientes escriban sus propias etiquetas de precio y nunca las verifica en la caja.

Este es el anti-patrón de **confiar en el cliente**. Todo lo que manda el cliente — un campo oculto de un formulario, un rol en una cookie, un flag `isAdmin=false` — **se puede falsificar.** El navegador, la app, el request: todo está bajo control del usuario. Cada chequeo real debe ocurrir en el **servidor**, que el usuario no puede editar. **El cliente es una sugerencia; el servidor es la autoridad.**

_Diagram: Todo lo que está del lado del cliente lo puede cambiar el usuario. Solo el servidor toma la decisión._

#### Trusting the Client (chequeos del lado del cliente)

- **Qué es:** Decisiones de permisos tomadas a partir de datos que mandó el cliente.
- **Cómo se ve:** Un rol en una cookie, un campo oculto, un flag `isAdmin` en el request.
- **Daño:** El usuario se otorga permisos a sí mismo.
- **Arreglo:** Cada chequeo en el servidor; el cliente solo sugiere.
- **Relaciones:** Una causa común de **Broken Access Control**.

> **La pregunta del fallo:** "Si un usuario altera el id, el token o el request, ¿mi servidor igual lo frena?"

> Casi toda filtración de auth es una de estas: un chequeo que se salteó, un secreto mal guardado, o un cliente al que se le creyó.

## 7. Hacerlo bien

La buena auth consiste sobre todo en usar herramientas probadas correctamente y verificar permisos sin descanso — no en ser ingenioso. Así se elige.

### Auth Provider — usá una librería o un proveedor

> No fabricás tus propios cinturones de seguridad — instalás unos certificados, diseñados por especialistas y probados en choques durante años.

Para casi todo el mundo, lo correcto es **no armar la auth por tu cuenta:** usá la auth de tu framework, o un **auth provider** (Auth0, Clerk, Supabase, Cognito y similares) que maneje el hashing, las sesiones, MFA, OAuth y los casos borde que nunca se te ocurrirían. Tu trabajo es integrarlo bien y encargarte de la **autorización** — la parte que solo vos conocés.

_Diagram: El proveedor maneja la identidad: hashes, sesiones, MFA, OAuth. Tu app es dueña de las reglas de acceso._

#### Auth Provider (librería o servicio de auth)

- **Problema:** La auth hecha a mano casi siempre termina con agujeros.
- **Idea:** Entregar la authN a una herramienta probada; quedarte con la authZ.
- **Ejemplo:** Auth0, Clerk, Supabase, Cognito, o la auth incorporada de tu framework.
- **Coste:** Una dependencia de un proveedor; hay que integrarlo bien.
- **Cuándo usarlo:** Casi siempre.
- **Relaciones:** Pone en práctica **Don't Roll Your Own Auth**.

### Match the mechanism to the app — elegí el mecanismo según la app

> Una llave de casa, una de auto y una tarjeta de hotel son todas «llaves» — elegís según la puerta, no según la moda.

**Sesiones** para una app web normal (simples, revocables al instante); **JWTs de vida corta más refresh** cuando necesitás escala sin estado entre servicios; **OIDC** para login social y SSO; **API keys** para máquina a máquina. Sumá **MFA** en todos lados donde importe, sobre todo en cuentas de admin. Elegí según la forma de tu app, no según lo que suena avanzado.

_Diagram: La necesidad a la izquierda, el mecanismo a la derecha. Elegí según la forma de la app._

#### Antes de lanzar la auth

- **¿Las contraseñas se hashean de forma lenta** (Argon2/bcrypt), y nunca se guardan como texto?
- **¿Hay MFA disponible**, y es obligatorio para los admins?
- **¿Cada endpoint verifica la authZ** — el rol _y_ la propiedad del objeto?
- **¿Los tokens van en cookies httpOnly**, de vida corta, y nunca en URLs ni en git?
- **¿El chequeo real está en el servidor**, sin confiar nunca en roles que manda el cliente?
- **¿Uso una librería/proveedor probado** en vez de un esquema armado a mano?

#### Señales de que está roto

- Cambiar un **id en la URL** muestra los datos de otro.
- Un **permiso vive en una cookie o campo oculto** que el cliente puede editar.
- Contraseñas guardadas en **texto plano o MD5**.
- **No hay forma de revocar** a un usuario logueado salvo esperar al vencimiento.
- **Sin MFA** en las cuentas que pueden hacer más daño.
- **Escribiste vos** tu propio esquema de tokens o de criptografía.

#### Señales de que lo hiciste bien

- La authN y la authZ están **separadas**, y la authZ se verifica en **cada request**.
- Cada acceso a un objeto verifica que **este usuario es dueño de esto**.
- Las credenciales están **hasheadas, acotadas, de vida corta y rotables.**
- El **servidor es la autoridad**; nada confía en el cliente.
- Podés **revocar el acceso** y ver **quién hizo qué** en un log.
- El trabajo pesado está en una **librería o proveedor probado**, no en tu propio código.

### Cómo se conecta todo

> El camino de un huésped de hotel: un pasaporte en la recepción, una tarjeta llave en la mano, y cada puerta decide por sí misma si abre.

Los factores de login (contraseña, MFA, passkey, OIDC, API key) llevan a la **authN**. Su resultado viaja con cada request en una **sesión** o un **JWT**, mejor guardado en una **cookie httpOnly**. En cada request, la **authZ** decide por roles o por política — y siempre verifica la **propiedad** del objeto.

_Diagram: De izquierda a derecha: factores → authN → sesión o JWT → authZ en cada request → roles/política + propiedad._

## Hoja de referencia: los 22 conceptos

### Dos preguntas

- **Authentication (authN)** (probar la identidad): Probar quién sos. Normalmente una vez por login.
- **Authorization (authZ)** (decidir permisos): Decidir qué podés hacer. En cada request.
- **Don't Roll Your Own Auth** (estándares antes que hacerlo a mano): Usar estándares y librerías probadas, no un esquema propio.

### Probar quién sos

- **Password Hashing** (hash lento con sal): Guardar un hash lento con sal (Argon2, bcrypt), nunca la contraseña.
- **MFA** (multifactor, 2FA): Un segundo factor: algo que tenés o que sos. La mejora grande más barata.
- **Passkeys** (WebAuthn): Un par de claves en el dispositivo, login por firma. Nada que phishear.

### Seguir logueado

- **Stateless HTTP** (sin memoria entre requests): El servidor olvida los requests — cada uno necesita un pase.
- **Session** (sesión del lado del servidor): La cookie tiene un id; la verdad está en el servidor. Revocación instantánea. El default.
- **JWT** (JSON Web Token): Un token firmado con claims adentro. Sin consulta, pero difícil de revocar.
- **httpOnly Cookie** (una cookie que JS no puede leer): Donde va un token del navegador. XSS no la puede leer.

### Acceso delegado

- **OAuth 2.0** (autorización delegada): Acceso a la cuenta de alguien con un token de alcance acotado, sin contraseña.
- **OIDC** (OpenID Connect): OAuth2 + un ID token: «y acá está quién es». Login social y SSO.
- **API Key** (credencial de máquina): Un secreto para programas. Alcance acotado, rotación, nunca en git ni en una URL.

### Permisos

- **Least Privilege** (denegar por defecto): «No» por defecto; conceder solo el mínimo necesario.
- **RBAC** (Role-Based Access Control): Permisos por rol: admin, editor, lector.
- **ABAC** (Attribute-Based Access Control): Permisos por una política sobre atributos del usuario, del recurso y del contexto.
- **Ownership Check** (authZ a nivel de objeto): No solo «qué rol» sino «de quién es el registro».

### Cómo se rompe

- **Broken Access Control / IDOR** (falta de chequeo de permisos): Se salteó el chequeo: cambiás el id en la URL, ves los datos de otro.
- **Plaintext / Fast Hash** (contraseñas en texto o MD5): Una filtración de la base — todas las contraseñas afuera.
- **Token Leakage** (tokens filtrados): Tokens en URLs, localStorage, git. Quien encuentre uno, entra.
- **Trusting the Client** (chequeos del lado del cliente): El cliente es una sugerencia; el servidor es la autoridad.

### Hacerlo bien

- **Auth Provider** (librería o servicio de auth): Entregá la authN a una herramienta probada; quedate con la authZ.

> La auth no es donde te ponés ingenioso. Es donde usás los estándares correctamente, denegás por defecto, y nunca, jamás, confiás en el cliente.

Fin del curso exprés · 7 capítulos · 22 conceptos

Lo que viene es profundidad: el OWASP Top 10 y sus hojas de referencia, las especificaciones de OAuth 2.0 y OpenID Connect, y las guías de tu propio auth provider. Pero llevá las dos preguntas a todos lados — ¿quién sos, y qué te está permitido hacer? La primera respondela con una herramienta probada, y la segunda en tu servidor, cada vez.
