Skip to main content

IAM REST API Reference

The IAM service handles authentication, RBAC, user management, and pluggable auth providers. All endpoints are served at https://api.septemcore.com/v1.

See the REST API Overview for authentication headers, error format, pagination, and rate limiting.

note

For layout brevity, the /api/v1 base path prefix is omitted from the endpoint tables below.


Group 1: Authentication

EndpointAuthDescription
POST /auth/registerRegister new user (email + password). Creates tenant + Owner role.
POST /auth/loginEmail + password login. Returns token pair or requiresTenantSelection.
POST /auth/login/:providerIdLogin via OAuth/wallet provider. Returns redirect URL.
GET /auth/callback/:providerIdOAuth callback handler. Returns token pair or requiresTenantSelection.
POST /auth/logoutInvalidate refresh token. Subsequent refresh with this token → 401.
POST /auth/refreshRotate access token using refresh token. Returns new token pair.
GET /auth/meCurrent authenticated user with roles and permissions.
POST /auth/impersonateusers.impersonatePlatform Owner only. Get scoped JWT for a tenant. Requires reason.

POST /api/v1/auth/login

Request:

{
"email": "[email protected]",
"password": "S3cur3P@ssw0rd!",
"mfaCode": "123456"
}

Response (single-tenant user):

{
"accessToken": "eyJhbGci...",
"refreshToken": "rt_01j9p...",
"expiresAt": "2026-04-22T03:15:00Z"
}

Response (multi-tenant user — no lastTenantId):

{
"requiresTenantSelection": true,
"sessionToken": "st_01j9p...",
"tenants": [
{ "id": "01j9pten0000000000000001", "name": "Acme Corp", "logoUrl": "https://...", "role": "admin" },
{ "id": "01j9pten0000000000000002", "name": "Beta Inc", "logoUrl": "https://...", "role": "member" }
]
}

mfaCode is required only if the user has 2FA enabled. Omit when 2FA is off.

POST /api/v1/auth/impersonate

Request:

{
"tenantId": "01j9pten0000000000000001",
"reason": "security_investigation",
"note": "Investigating suspicious login from IP 1.2.3.4 per ticket SEC-451"
}

Response: standard token pair with tenantId scoped to the target tenant. TTL: 1 hour. Audit record: auth.impersonation.started.


Group 2: MFA (Two-Factor Authentication)

EndpointAuthDescription
POST /auth/mfa/enableGenerate TOTP secret + QR code. User scans in Authenticator app.
POST /auth/mfa/verifyConfirm TOTP setup by entering a code. Activates 2FA.
POST /auth/mfa/disableDisable 2FA. Requires current password + active TOTP code.
POST /auth/recoveryEmergency login via recovery code. Allows resetting email+password+2FA.
GET /auth/recovery-codesReturns count of remaining recovery codes.
POST /auth/recovery-codes/regenerateGenerate 10 new recovery codes. Invalidates old codes.

Recovery Code Security

ParameterValue
Count per user10 codes, generated at registration and at 2FA enable
FormatRandom alphanumeric strings, each single-use
Storageargon2id hash in PostgreSQL — plaintext shown only once at generation
Rate limit5 attempts / 15 minutes (RECOVERY_MAX_ATTEMPTS). Exceeded → 1-hour lock + Owner email alert
Hard lockAfter 15 failed attempts (3 lockout cycles) → account status=locked + Platform Admin alert

Group 3: Security Flows

EndpointAuthDescription
POST /auth/verify-emailConfirm email address from verification token. TTL: 24h.
POST /auth/request-resetRequest password-reset email. One-time token sent via Notify.
POST /auth/reset-passwordReset password using one-time token from email. TTL: 1h.
POST /auth/inviteusers.createInvite user by email with pre-assigned role. TTL: 72h.
POST /auth/accept-inviteAccept invitation — set password, complete registration.

Request — POST /api/v1/auth/invite:

{
"email": "[email protected]",
"roles": ["support-manager"]
}

Group 4: Auth Providers

EndpointAuthDescription
GET /auth/providersList installed auth providers for login page rendering.
POST /users/:id/providers/:providerIdLink an additional auth provider to an existing account.
DELETE /users/:id/providers/:providerIdUnlink a provider. Rejected if it's the last linked provider.
GET /users/:id/providersList all provider links for a user.

Provider Object

{
"id": "01j9pprov000000000000001",
"providerId": "google",
"providerType": "oauth",
"externalId": "accounts.google.com|117982...",
"email": "[email protected]",
"displayName": "Google — [email protected]",
"linkedAt": "2026-04-01T09:00:00Z"
}

Uniqueness constraint: (providerId, externalId) is unique across all users. Attempting to link a Google account already linked to another user → 409 Conflict.


Group 5: Users

EndpointAuthDescription
POST /usersusers.createCreate user in the current tenant.
GET /usersusers.listList users (paginated). Default excludes deleted.
GET /users/:idusers.listUser details with roles and permission summary.
PATCH /users/:idusers.updatePartial update (name, email, status).
DELETE /users/:idusers.deleteSoft delete (blocks login, retains data).
PATCH /users/:id/restoreusers.updateRestore soft-deleted user (re-enables login).
POST /users/:id/rolesroles.assignAssign a role to user.
DELETE /users/:id/roles/:roleroles.assignRevoke a role from user.

User Object

{
"id": "01j9pusr0000000000000001",
"email": "[email protected]",
"firstName": "Alice",
"lastName": "Johnson",
"avatarUrl": "https://cdn.platform.io/assets/avatars/alice.webp",
"tenantId": "01j9pten0000000000000001",
"roles": ["admin", "billing-viewer"],
"emailVerified": true,
"mfaEnabled": true,
"status": "active",
"createdAt": "2026-04-01T10:00:00Z",
"updatedAt": "2026-04-20T14:30:00Z",
"deletedAt": null
}

RBAC Limits

ParameterLimitNotes
Max roles per user50Permissions union resolved at Gateway (Valkey cache)
Max permissions per role1,000Exceeding = 400 (rbac-limit-exceeded)
Max roles per tenant500Exceeding = 400 (rbac-limit-exceeded)

Group 6: RBAC — Roles & Permissions

Roles are created from atomic permissions. There are no built-in non-platform roles — tenant admins compose roles from available permissions.

EndpointAuthDescription
GET /rolesroles.listList all roles for this tenant (cursor-paginated).
POST /rolesroles.createCreate a new role with a set of permissions.
GET /roles/:idroles.listRole details with full permissions list.
PATCH /roles/:idroles.updateUpdate role permissions.
DELETE /roles/:idroles.deleteDelete custom role (built-in roles cannot be deleted).
GET /permissionsroles.listList all registered permissions from all modules.
GET /users/:id/permissionsusers.listResolved permission list for user (union of roles).

POST /api/v1/roles

{
"name": "Support Manager",
"description": "Can read contacts, close tickets, cannot delete.",
"permissions": [
"crm.contacts.read",
"crm.tickets.read",
"crm.tickets.close",
"audit.read"
]
}

Wildcard Permissions

PermissionEffect
crm.*Full access to all CRM module operations
crm.contacts.readGranular: read-only on contacts
billing.*Full billing access

Resolution: Gateway checks exact match first, then wildcard {module}.*. Platform-reserved permissions (system.*, platform.*) cannot be registered by modules.

Role Object

{
"id": "01j9prole000000000000001",
"name": "Support Manager",
"description": "Can read contacts, close tickets.",
"permissions": ["crm.contacts.read", "crm.tickets.read"],
"tenantId": "01j9pten0000000000000001",
"createdBy": "01j9pusr0000000000000001",
"createdAt": "2026-04-10T08:00:00Z"
}

Group 7: Multi-Tenant

EndpointAuthDescription
GET /auth/tenantsList all tenants the user belongs to.
POST /auth/select-tenant❌ (session)Select tenant during login flow. Returns full JWT.
POST /auth/switch-tenantSwitch active tenant without re-login. Returns new token pair.

POST /api/v1/auth/select-tenant

Called after receiving requiresTenantSelection: true from login:

{
"sessionToken": "st_01j9p...",
"tenantId": "01j9pten0000000000000001",
"rememberChoice": true
}

rememberChoice: true saves lastTenantId — next login auto-selects this tenant.

POST /api/v1/auth/switch-tenant

{
"tenantId": "01j9pten0000000000000002"
}

Response: new full token pair scoped to the target tenant. The refresh token is tenant-scoped — one stolen token does not give access to the user's other tenants.


Error Reference

Error typeStatusTrigger
problems/invalid-credentials401Wrong email or password
problems/mfa-required4012FA enabled but mfaCode not provided
problems/mfa-invalid401TOTP code incorrect or expired
problems/token-expired401Access or refresh token expired
problems/account-locked403Account locked after failed recovery attempts
problems/forbidden403Insufficient permission for operation
problems/rbac-limit-exceeded400Role/permission count exceeds plan limit
problems/provider-already-linked409OAuth provider already linked to another user
problems/last-provider400Cannot unlink the last auth provider
problems/transfer-in-progress409Tenant ownership transfer already pending