Mensaje de error
IDX10223: Lifetime validation failed. The token is expired.
También se muestra como
- Bearer error="invalid_token", error_description="The token expired at '10/20/2026 06:28:30'"
- IDX10222: Lifetime validation failed. The token is not yet valid.
El texto que sigue a «The token is expired.» contiene ambas marcas de tiempo en el formato de la referencia cultural (culture) del servidor. La descripción de `WWW-Authenticate` de ASP.NET Core la genera `JwtBearerHandler`.
Microsoft.IdentityModel.Tokens (.NET) — SecurityTokenExpiredException
Qué significa
El `exp` del token es anterior a la hora actual menos `ClockSkew` (5 minutos por defecto). La firma y los demás claims pueden ser válidos; simplemente, el token está fuera de su vida útil. El mensaje sigue con «ValidTo (UTC): …, Current time (UTC): …», y ASP.NET Core informa al cliente con `error_description="The token expired at '…'"`. IDX10222 es el caso contrario: `nbf` está en el futuro.
Por qué ocurre
La vida útil del token ya terminó
frecuenteLos tokens de acceso de Entra ID duran entre 60 y 90 minutos por defecto; los de otros proveedores, a menudo entre 5 y 15 minutos. Un cliente que sigue usando el mismo token después de `exp` falla justo a la hora prevista.
Desfase de reloj superior a la tolerancia
ocasionalCon un `ClockSkew` reducido (por ejemplo, `TimeSpan.Zero`, que se copia y pega a menudo), incluso unos segundos de desfase entre el emisor y la API hacen que se rechacen tokens recién emitidos.
Un token almacenado en caché fuera de la biblioteca de tokens
ocasionalLos tokens guardados en una base de datos, en un campo estático o en un archivo de configuración nunca se actualizan. MSAL y bibliotecas similares los actualizan automáticamente si se lo permites.
Cómo solucionarlo
- 1.
Mantener pequeña la tolerancia al desfase de reloj
Tolera un desfase de segundos, no de minutos, y corrige los relojes. Nunca establezcas `ValidateLifetime = false` en producción.
csharp options.TokenValidationParameters = new TokenValidationParameters { ValidIssuer = "https://login.example.com/", ValidAudience = "api://orders", ClockSkew = TimeSpan.FromSeconds(30), // default is 5 minutes; lower it, do not raise it to hide expiry }; - 2.
Obtener los tokens a través de la biblioteca en cada llamada
`AcquireTokenSilent` devuelve un token válido de la caché o lo actualiza, así que la caducidad se resuelve antes de la solicitud.
csharp // Client side (MSAL): ask for a token every time; MSAL returns the cached one or refreshes it. var result = await app.AcquireTokenSilent(scopes, account).ExecuteAsync(); httpClient.DefaultRequestHeaders.Authorization = new("Bearer", result.AccessToken);