Skip to main content
The JWT issued by POST /api/Auth is a signed token that carries all identity and permission data the API needs to authorize requests. You never need to look inside the token during normal operation — but understanding its structure helps when debugging access issues.

Sending the token

Include the token in the Authorization header on every request to a protected endpoint:
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
Omitting the header or sending a malformed token results in 401 Unauthorized. Make sure there is exactly one space between Bearer and the token value, with no trailing characters.

Token properties

PropertyValue
AlgorithmHMAC-SHA256 (HS256)
Lifetime30 minutes from issue time
MechanismStateless — no server-side session
RefreshNot supported — re-authenticate when expired

Claims reference

The token payload contains the following claims:
Claim typeKey in tokenTypeDescription
ClaimTypes.NameIdentifiersub (or nameid)stringThe user’s unique ID in the identity store
ClaimTypes.Nameunique_namestringThe user’s username
perfilIdperfilIdstring (integer)The numeric ID of the profile assigned to the user
esAdminesAdminstring"true" if the profile has administrator flag set, otherwise "false"
permisopermisostring (repeated)One claim per granted permission, e.g. "usuario.agregar". Multiple permiso claims may be present.
esAdmin and perfilId are custom claims added by AuthService. Standard ASP.NET Core Identity claims use the full ClaimTypes.* URIs internally but may appear with short names when decoded at jwt.io.

The permiso claim

Permissions are embedded as repeated claims — one permiso entry per granted action. A user with access to two modules may have a token that contains:
{
  "permiso": [
    "usuario.agregar",
    "usuario.consultar",
    "perfil.consultar"
  ]
}
If the user’s profile has BitAdministrador = true, the token will contain one permiso claim for every action on every module registered in the system. See Permissions for the full list.

Decoded token example

A decoded JWT payload for a non-admin user might look like this:
{
  "nameid": "abc-123-user-id",
  "unique_name": "jdoe",
  "perfilId": "2",
  "esAdmin": "false",
  "permiso": [
    "usuario.consultar",
    "usuario.detalle",
    "perfil.consultar"
  ],
  "nbf": 1743000000,
  "exp": 1743001800,
  "iss": "WebCorporativaAPI",
  "aud": "WebCorporativaAPI"
}

How to decode the token

Using jwt.io

Paste the raw token string into jwt.io. The site decodes the header and payload without verifying the signature. Use this for quick inspection during development.
Do not paste production tokens into public tools. Use jwt.io only in development with non-sensitive tokens.

Using C# (JwtSecurityTokenHandler)

using System.IdentityModel.Tokens.Jwt;

var handler = new JwtSecurityTokenHandler();
var jwt = handler.ReadJwtToken(rawToken);

// Read a single claim
var userId = jwt.Claims.First(c => c.Type == "nameid").Value;
var isAdmin = jwt.Claims.First(c => c.Type == "esAdmin").Value;

// Read all permiso claims
var permissions = jwt.Claims
    .Where(c => c.Type == "permiso")
    .Select(c => c.Value)
    .ToList();
In a real ASP.NET Core application you do not need to decode the token manually. The JWT middleware populates HttpContext.User.Claims automatically after validating the token. Use User.TienePermiso("modulo.accion") (defined in ClaimsExtensions) to check permissions.

Authentication overview

The full login flow from credentials to protected request.

Permissions

How the permiso claims map to specific API endpoints.

Build docs developers (and LLMs) love