Skip to main content
Version: Latest

8. Login

8.1 Endpoint

POST api/Tokens/Create
  • Controller: TokensController ([Route("api/[controller]")]api/Tokens, [AllowAnonymous], [TenantIdHeader]).
  • Required header: TenantId: {tenantId} — note this is the header name TenantId, not X-Tenant or any X- prefixed variant.
  • Request body: TokenRequest(string PhoneNumber, string Password) (a record, positional parameters).

8.2 Tenant database provisioning — not triggered by registration

Registration (Chapter 5) does not provision the tenant's application database. For a tenant that already existed at the last application startup, provisioning happens via DatabaseInitializer.InitializeDatabasesAsync, a Hangfire-enqueued, per-tenant loop that runs only for already-verified, already-active, non-root tenants at app startup.

For a brand-new tenant (registered after the app was already running), that startup loop never sees it. Provisioning instead happens via a synchronous inline fallback inside TokenService.GetTokenAsync — confirmed empirically:

  1. First login attempt after verification returns HTTP 423 with body "tenant_provisioning_in_progress" while migrations and seeding run in the background/inline.
  2. A later retry succeeds once seeding completes — confirmed via the full seed-pipeline log trace ending in "Seeded default notification delivery policies for tenant", the last step in ApplicationDbSeeder.SeedDatabaseAsync's pipeline.

Frontend implication: the login screen must handle 423 as "still provisioning, retry shortly" — not as an authentication failure — for any tenant that just completed activation.

8.3 Success response

{
"data": { "token": "...", "refreshToken": "...", "..." : "..." },
"statusCode": 200,
"succeeded": true,
"messages": ["..."]
}

The JWT carries TenantId, Identifier, role, and permission claims — read via ICurrentUser on subsequent requests.

8.4 Verified dev credential pattern

Every tenant's admin user is seeded via SeedAdminUserAsync with the same hardcoded default password (DefaultAdminConstants.Password). For the newly-registered dev tenant, the admin phone number is the adminPhoneNumber submitted at registration. Login succeeded on the first retry after the 423 provisioning window closed.