Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/CodexaCP/DG_BACK/llms.txt

Use this file to discover all available pages before exploring further.

Dragon Guard JWT tokens carry user identity, tenant scope, and role information as standard claims. Understanding the claims structure is essential for implementing client-side role checks, building multi-tenant UIs, and debugging authorization failures. All tokens are signed with HMAC SHA-256 using the secret configured in Jwt:Key.

Claims reference

The following claims are present in every Dragon Guard JWT unless noted otherwise.
ClaimTypeAlways presentDescription
userIdstringThe user’s unique identifier (auth.Users.Id as a UUID string). For GrupoMAS delegated sessions this is a deterministic UUID derived from GrupoMASNative:<companyId>:<username>.
emailstringThe user’s email address. For GrupoMAS sessions this is the email returned by MAS, or the username when MAS returns no email.
isSuperAdminstring"True" or "False". When "True" the account is SUPERADMIN_SUPREMO with global platform access and no tenant scope.
isHandheldstring"True" when the token was issued by the handheld login endpoint.
authProviderstringIdentifies the authentication source. See authProvider values.
company_accessstring⚠️ per companyOne claim per authorized company. Value is the companyId UUID string. Omitted for SUPERADMIN_SUPREMO.
company_rolestring⚠️ per companyOne claim per authorized company in companyId:roleCode format (e.g. 1b9d6bcd-...:ADMIN). Used for per-company role resolution. Omitted for SUPERADMIN_SUPREMO.
companyIdstring⚠️ non-supremeThe default company context (UUID string). Set to the first company in the user’s access list. Omitted for SUPERADMIN_SUPREMO.
rolestringGlobal role claim. SUPERADMIN_SUPREMO for supreme accounts; the user’s role code for tenant accounts.
http://schemas.microsoft.com/ws/2008/06/identity/claims/rolestringASP.NET Core ClaimTypes.Role — same value as role. Required for [Authorize(Roles = "...")] attributes.
externalUsernamestring⚠️ handheldThe normalized MAS username. Present only on GrupoMAS delegated sessions (authProvider = GrupoMASNative).
deviceIdstring⚠️ handheldThe normalized device MAC address (e.g. AA:BB:CC:DD:EE:FF). Present only on handheld tokens when a deviceId was supplied.

authProvider values

The authProvider claim identifies how the user authenticated. Dragon Guard currently issues tokens with two provider values:
ValueAuth flowNotes
DragonGuardLocalStandard POST /api/auth/loginEmail/password verified against auth.Users.PasswordHash using BCrypt. Default value when no override is supplied.
GrupoMASNativePOST /api/auth/grupomas-handheld-loginCredentials delegated to the GrupoMAS ERP. No local password is stored. POST /api/auth/change-password is blocked for these sessions.

SUPERADMIN_SUPREMO token structure

Supreme administrator accounts (auth.Users.IsSuperAdmin = 1) receive a different token shape than tenant users:
  • isSuperAdmin is "True"
  • role is "SUPERADMIN_SUPREMO"
  • No company_access claims
  • No company_role claims
  • No companyId claim
ApiControllerBase.HasCompanyAccess grants unconditional access when isSuperAdmin = true, bypassing the company_access check. Supreme endpoints under api/supreme/* additionally call EnsureSupremeAccess() which explicitly rejects non-supreme tokens.
Never use the presence or absence of company_access claims alone to gate functionality. Always check isSuperAdmin first — supreme tokens intentionally carry no company claims but must still access all tenant resources.

Company context resolution

ApiControllerBase.ResolveCompanyId determines the active tenant for every protected request. Resolution follows a strict priority order:
1

1 — companyId query parameter

If companyId is present in the query string and is a valid UUID, it is used. The value is immediately validated against the token’s company_access claims — an unrecognized company ID is rejected with 401 Unauthorized.
GET /api/inventory?companyId=1b9d6bcd-bbfd-4b2d-9b5d-ab8dfbbd4bed
Authorization: Bearer <token>
2

2 — X-Company-Id request header

If the X-Company-Id header is present and is a valid UUID, it is used. The same access check applies.
GET /api/inventory
Authorization: Bearer <token>
X-Company-Id: 1b9d6bcd-bbfd-4b2d-9b5d-ab8dfbbd4bed
3

3 — companyId JWT claim

If neither of the above are present, the companyId claim embedded in the JWT is used. This is the default company set at login time. SUPERADMIN_SUPREMO tokens have no companyId claim; supreme requests must supply the company via query parameter or header.
Never pass an arbitrary companyId and expect it to work without token backing. All three resolution paths call EnsureCompanyAccess, which verifies the resolved company is present in the token’s company_access claims (or the user is SUPERADMIN_SUPREMO).

Role resolution

ApiControllerBase.Role uses the following logic to determine the effective role for the current request:
  1. If IsSupremeAdmin is true, return "SUPERADMIN_SUPREMO" immediately.
  2. Resolve the effective company via ResolveCompanyId().
  3. Search the token’s company_role claims for a claim whose companyId segment matches the resolved company. Return the roleCode segment from that claim.
  4. If no matching company_role claim is found, fall back to the global role claim.
This means a user’s effective role can vary by company when they have multiple company_role claims. The fallback to role ensures backward compatibility with tokens issued before per-company role claims were introduced.

Token validation configuration

Dragon Guard validates incoming JWTs using the following TokenValidationParameters settings — all four validation checks are enabled:
ParameterEnabledNotes
ValidateIssuerIssuer must match Jwt:Issuer from server configuration.
ValidateAudienceAudience must match Jwt:Audience from server configuration.
ValidateLifetimeToken expiry is enforced. Expiry duration is set by Jwt:ExpiresInMinutes.
ValidateIssuerSigningKeySignature is verified against the HMAC SHA-256 key in Jwt:Key.
Tokens are signed with HMAC SHA-256. Use a strong, randomly generated secret for Jwt:Key in production — minimum 32 characters. Short or predictable keys can be brute-forced, allowing an attacker to forge arbitrary tokens. Rotate the key immediately if it is ever exposed.

Build docs developers (and LLMs) love