Skip to main content
WebCorporativa uses a role-based access control (RBAC) model where permissions are granted at the module + action level, attached to a user profile, and embedded directly in the JWT. The API checks permissions on every protected endpoint without a separate authorization server call.

How permissions work

1

Assign permissions to a profile

Use the POST /api/PermisoPerfil/guardar-permisos endpoint to grant specific module actions to a profile. Each permission is a combination of a module key and an action name.
2

Assign the profile to a user

Every user has exactly one profile (perfilId). When the user logs in, the API reads the profile’s permission set.
3

Permissions are embedded in the JWT

Each granted permission becomes a permiso claim in the issued token. The API never queries the database again to check permissions during a request — everything is in the token.
4

Endpoint enforces the permission

Protected endpoints call user.TienePermiso("modulo.accion"). If the claim is not present, the endpoint returns 403 Forbidden.

Permission format

Every permission string follows the pattern:
{moduleKey}.{action}
For example:
  • usuario.agregar — create users
  • perfil.editar — edit profiles
  • modulo.eliminar — delete modules

Actions

Five actions are defined for every module:
ActionMeaning
agregarCreate a new record
editarModify an existing record
eliminarDelete a record
consultarList or search records
detalleRetrieve a single record by ID

Administrator bypass

If a user’s profile has BitAdministrador = true, the API injects permission claims for all actions on all modules into the JWT at login time. The esAdmin claim is also set to "true". The permission check short-circuits for admins:
public static bool TienePermiso(this ClaimsPrincipal user, string permiso)
{
    if (user.Claims.Any(c => c.Type == "esAdmin" && c.Value.Equals("true", StringComparison.OrdinalIgnoreCase)))
        return true;

    return user.Claims
        .Where(c => c.Type == "permiso")
        .Any(c => c.Value == permiso);
}
An administrator’s JWT will contain every permiso claim for every registered module. If new modules are added to the system, the administrator must log out and back in to receive updated permissions in a new token.

HTTP responses for authorization failures

ScenarioHTTP status
No token or invalid token401 Unauthorized
Valid token but missing required permission403 Forbidden
A 403 Forbidden response means the user is authenticated but their profile does not grant the required permission. Re-authenticating will not help — the profile itself must be updated via POST /api/PermisoPerfil/guardar-permisos.

Built-in module permissions

The following table lists every permission string for all built-in modules. Custom modules you create follow the same pattern using the Clave field you set when creating them.
Moduleagregareditareliminarconsultardetalle
modulomodulo.agregarmodulo.editarmodulo.eliminarmodulo.consultarmodulo.detalle
perfilperfil.agregarperfil.editarperfil.eliminarperfil.consultarperfil.detalle
permisosperfilpermisosperfil.agregarpermisosperfil.editarpermisosperfil.eliminarpermisosperfil.consultarpermisosperfil.detalle
usuariousuario.agregarusuario.editarusuario.eliminarusuario.consultarusuario.detalle
principal11principal11.agregarprincipal11.editarprincipal11.eliminarprincipal11.consultarprincipal11.detalle
principal12principal12.agregarprincipal12.editarprincipal12.eliminarprincipal12.consultarprincipal12.detalle
principal21principal21.agregarprincipal21.editarprincipal21.eliminarprincipal21.consultarprincipal21.detalle
principal22principal22.agregarprincipal22.editarprincipal22.eliminarprincipal22.consultarprincipal22.detalle

Checking permissions in the JWT

You can verify which permissions a token carries by decoding it. A non-admin user token with profile-level access might include:
{
  "esAdmin": "false",
  "permiso": [
    "usuario.consultar",
    "usuario.detalle",
    "perfil.consultar"
  ]
}
An admin token for a system with two modules would include:
{
  "esAdmin": "true",
  "permiso": [
    "modulo.agregar",
    "modulo.editar",
    "modulo.eliminar",
    "modulo.consultar",
    "modulo.detalle",
    "usuario.agregar",
    "usuario.editar"
  ]
}
Use the decoded JWT to debug 403 errors during development. Confirm the required permission string is present in the permiso claims before assuming the endpoint is broken.

JWT structure

How claims are structured and how to decode the token.

Authentication overview

The full login flow, token lifetime, and 401 handling.

Build docs developers (and LLMs) love