Porta v1.11.0
Skip to content

Users API ​

Manage users within an organization. Users are the end-user accounts that authenticate through Porta's OIDC endpoints.

Base path: /api/admin/organizations/:orgId/users

Create User ​

http
POST /api/admin/organizations/:orgId/users
FieldTypeRequiredDescription
emailstring✅Email address (must be unique within org)
given_namestringFirst name
family_namestringLast name
nicknamestringNickname
passwordstringPassword (NIST SP 800-63B compliant)
phone_numberstringPhone number
localestringUser locale (e.g., en)
picturestringProfile picture URL
json
{
  "email": "alice@example.com",
  "given_name": "Alice",
  "family_name": "Smith",
  "password": "a-secure-password-here"
}

Response: 201 Created

Invite User ​

http
POST /api/admin/organizations/:orgId/users/invite

Permission: user:invite

Creates a pending invitation and sends an enhanced invitation email. No account is created at invite time; the recipient's account is created only when they accept the invitation and set a password. Supports optional personal message, role/claim pre-assignment, and inviter tracking. Pre-assigned roles and claims are stored with the invitation and automatically applied on acceptance.

FieldTypeRequiredDescription
emailstring✅Email address
givenNamestringFirst name (OIDC standard claim)
familyNamestringLast name (OIDC standard claim)
personalMessagestringPersonal message from the admin (max 500 chars, included in email)
rolesarrayRoles to pre-assign on acceptance
roles[].applicationIduuid✅Application the role belongs to
roles[].roleIduuid✅Role ID to assign
claimsarrayCustom claim values to pre-assign on acceptance
claims[].applicationIduuid✅Application the claim belongs to
claims[].claimDefinitionIduuid✅Claim definition ID
claims[].valueany✅Claim value
localestringLocale for the invitation email (default: org default)

Response: 201 Created. Returns 409 Conflict when the email already has an account in the organization or a live invitation already exists for it.

json
{
  "data": {
    "invitationId": "uuid",
    "email": "user@example.com",
    "invitationSent": true,
    "expiresAt": "2026-01-08T00:00:00.000Z"
  }
}

Pre-assignment behavior:

  • Referenced applications, roles, and claim definitions are validated at invite time
  • Pre-assignments are applied automatically when the invitation is accepted
  • If a role or claim is deleted between invitation and acceptance, that assignment is skipped (best-effort)
  • A new invitation replaces any live invitation for the same email address

Preview Invitation Email ​

http
POST /api/admin/organizations/:orgId/users/invite/preview

Permission: user:invite

Renders the invitation email without sending it. Returns the HTML, plain text, and subject line for admin review before sending.

FieldTypeRequiredDescription
emailstring✅Recipient email (for template personalization)
givenNamestringFirst name (OIDC standard claim)
familyNamestringLast name (OIDC standard claim)
personalMessagestringPersonal message to include
localestringLocale for rendering

Response: 200 OK

json
{
  "data": {
    "html": "<html>...</html>",
    "text": "Plain text version...",
    "subject": "John Doe has invited you to Acme Corp"
  }
}

List Users ​

http
GET /api/admin/organizations/:orgId/users

Supports page, pageSize, search, status, sort, order parameters. Search queries match against email, given name, family name, and nickname.

Response: 200 OK — Paginated user list.

Get User ​

http
GET /api/admin/organizations/:orgId/users/:userId

Response: 200 OK — Full user profile.

Update User ​

http
PUT /api/admin/organizations/:orgId/users/:userId

Updatable fields: given_name, family_name, nickname, phone_number, locale, picture.

INFO

Email changes are not supported through this endpoint to prevent authentication issues.

Response: 200 OK

Status Lifecycle ​

Users have three possible statuses (UserStatus): active, inactive, and locked. Administrators can activate and deactivate users. The server uses locked only for automatic failed-login lockout and cooldown recovery. Invitation is a pending token flow, not a status and not an account: no user row exists until the recipient accepts. On acceptance the account is created active and the recipient sets a password.

Status Transition Endpoints ​

http
POST /api/admin/organizations/:orgId/users/:userId/deactivate
POST /api/admin/organizations/:orgId/users/:userId/activate

Each returns 204 No Content.

Set Password ​

http
POST /api/admin/organizations/:orgId/users/:userId/password
FieldTypeRequiredDescription
passwordstring✅New password (NIST SP 800-63B compliant)

Passwords are hashed with Argon2id before storage.

Response: 200 OK

User Roles ​

See Roles & Permissions API for user-role assignment endpoints at:

/api/admin/organizations/:orgId/users/:userId/roles

User Claims ​

See Custom Claims API for user claim value endpoints.

User 2FA ​

Manage two-factor authentication for individual users. All endpoints require the admin:user:2fa permission.

Get 2FA Status ​

http
GET /api/admin/organizations/:orgId/users/:userId/two-factor/status

Permission: admin:user:read

Returns the user's current 2FA enrollment status, method, and recovery code count.

Response (200):

json
{
  "enabled": true,
  "method": "email",
  "totpConfigured": false,
  "recoveryCodesRemaining": 10
}
FieldTypeDescription
enabledbooleanWhether 2FA is currently enabled
method"email" | "totp" | nullActive 2FA method, null if disabled
totpConfiguredbooleanWhether a TOTP authenticator is configured
recoveryCodesRemainingnumberNumber of unused recovery codes

Disable 2FA ​

http
POST /api/admin/organizations/:orgId/users/:userId/two-factor/disable

Permission: admin:user:2fa

Force-disables 2FA for a user, removing their TOTP configuration and recovery codes. Protected by super-admin guard — cannot disable the super-admin user's 2FA.

Response (200):

json
{ "message": "Two-factor authentication disabled" }

Error responses:

StatusReason
4002FA is not currently enabled for this user
403Target user is the super-admin (protected)
404User not found in this organization

Reset 2FA ​

http
POST /api/admin/organizations/:orgId/users/:userId/two-factor/reset

Permission: admin:user:2fa

Resets 2FA by disabling it and clearing all enrollment data, forcing the user to re-enroll. Protected by super-admin guard.

Response (200):

json
{ "message": "Two-factor authentication reset" }

Regenerate Recovery Codes ​

http
POST /api/admin/organizations/:orgId/users/:userId/two-factor/recovery-codes/regenerate

Permission: admin:user:2fa

Generates a new set of 10 recovery codes, invalidating all previous codes. The new plaintext codes are returned once — they cannot be retrieved again. Protected by super-admin guard.

Response (200):

json
{
  "recoveryCodes": ["A1B2C3D4E5", "F6G7H8I9J0", "..."]
}

Organization 2FA Policy ​

Manage the organization-level 2FA enforcement policy.

Get Policy ​

http
GET /api/admin/organizations/:orgId/two-factor/policy

Permission: admin:org:read

Response (200):

json
{
  "twoFactorPolicy": "optional"
}

Update Policy ​

http
PUT /api/admin/organizations/:orgId/two-factor/policy

Permission: admin:org:update

FieldTypeRequiredDescription
twoFactorPolicystringYesOne of: optional, required_email, required_totp, required_any

Response (200):

json
{
  "twoFactorPolicy": "required_email"
}

Get 2FA Summary ​

http
GET /api/admin/organizations/:orgId/two-factor/summary

Permission: admin:org:read

Returns aggregate 2FA enrollment statistics for the organization.

Response (200):

json
{
  "totalUsers": 50,
  "enabledCount": 35,
  "disabledCount": 15,
  "totpCount": 20,
  "emailCount": 15,
  "complianceRate": 0.7
}
FieldTypeDescription
totalUsersnumberTotal users in the organization
enabledCountnumberUsers with 2FA enabled
disabledCountnumberUsers without 2FA
totpCountnumberUsers using TOTP method
emailCountnumberUsers using email OTP method
complianceRatenumberRatio of enabled/total (0–1, 4 decimal places)

Account Lockout ​

Porta automatically locks accounts after repeated failed login attempts (default: 5 attempts). Locked accounts auto-unlock after a cooldown period (default: 15 minutes). Administrators cannot manually lock or unlock accounts.

Lockout thresholds are configurable via the System Configuration API:

  • account_lockout_threshold — Number of failed attempts before auto-lock (default: 5)
  • account_lockout_cooldown_minutes — Minutes before auto-unlock (default: 15)

See the Deployment Guide for full details.

GDPR Data Export ​

http
GET /api/admin/organizations/:orgId/users/:userId/export

Exports all personal data for a user as a JSON document (GDPR Article 20 — data portability). The export includes:

  • User profile (email, name, phone, locale, etc.)
  • Organization membership
  • Role assignments (with role names and application context)
  • Custom claim values (with claim definitions)
  • Audit log entries related to the user
  • Two-factor authentication enrollment status
  • Active OIDC sessions and grants

Response: 200 OK — JSON document containing all user data.

Delete User ​

http
DELETE /api/admin/organizations/:orgId/users/:userId

Permanently deletes the user and owned identity and security data in one database transaction. Affected server-backed sessions and tokens are revoked. Historical audit entries remain under the configured audit retention policy and may still identify the deleted user.

Permission: admin:user:delete

Response: 204 No Content

Irreversible

Deletion cannot be undone. A control-plane user cannot be deleted when that would leave no other active user with the exact built-in porta-super-admin role.

Standalone User Routes ​

In addition to the org-scoped routes above, a set of standalone user routes is available at /api/admin/users/:userId. These provide direct access to user detail and mutation operations by user ID, without requiring the organization ID in the URL path.

Base path: /api/admin/users/:userId

These routes support administrative clients that navigate by user ID without an organization slug. They delegate to the same service functions and require the same admin authentication and RBAC permissions as the organization-scoped routes.

Available Standalone Endpoints ​

MethodPathDescriptionPermission
GET/:userIdGet user by IDuser:read
PUT/:userIdUpdate user profileuser:update
POST/:userId/deactivateDeactivate useruser:lifecycle
POST/:userId/activateActivate useruser:lifecycle
POST/:userId/passwordSet passworduser:update
DELETE/:userId/passwordClear passworduser:update
POST/:userId/verify-emailMark email verifieduser:update
GET/:userId/historyChange historyuser:read

TIP

The activate endpoint performs the inactive → active status transition.

Released under the MIT License.