Skip to content

Users ​

Users are the individuals who authenticate through AuthHero. Each user belongs to one or more tenants and can have different attributes and permissions.

User Properties ​

Each user has:

  • user_id: Unique identifier (format: {connection}|{id})
  • email: Email address
  • email_verified: Whether the email has been verified
  • name: Full name
  • nickname: Display name
  • picture: Profile picture URL
  • user_metadata: Custom data editable by the user
  • app_metadata: Custom data editable by administrators only
  • identities: Array of linked authentication identities
  • blocked: Auth0-parity account block flag (see Blocking a User)
  • login_count / last_login / last_ip: Login activity counters (see Login Activity)

Blocking a User ​

Setting blocked: true disables an account without deleting it:

http
PATCH /api/v2/users/{user_id}
{
  "blocked": true
}

Effects:

  • All authentication is refused — password, passwordless/OTP, social and enterprise logins, silent auth, and token exchange fail with 403 access_denied ("User is blocked"). Password logins are checked after credential validation, so the block status is never leaked to someone without valid credentials.
  • Refresh tokens stop working — the refresh_token grant returns invalid_grant with "User is blocked".
  • Existing sessions are revoked — on the transition into blocked, every session and its refresh tokens are revoked and a SUCCESS_REVOCATION log event is written. Already-issued access tokens are stateless JWTs and remain valid until they expire.

Blocking always operates on the primary account: blocking it blocks every linked identity, and a blocked value sent in an update targeting a linked identity is applied to the primary so it can't silently do nothing.

Unblock with blocked: false (this revokes nothing). You can filter on the flag with GET /api/v2/users?q=blocked:true.

SCIM inbound provisioning maps active: false to blocked: true (and vice versa), with the same session revocation on deactivation. Note that the admin UI has no blocked toggle yet — blocking is Management API / SCIM only today.

Login Activity ​

login_count, last_login, and last_ip appear on user records returned by the Management API and can be used in q= filters and sorts (e.g. q=login_count:0 finds users who never logged in). They are stored in a separate write-often user_activity table (see the database schema) — joined into user reads transparently — so the profile row isn't rewritten on every login.

The same table backs the failed-password lockout window (failed_logins) and last_password_reset; those fields are internal to the authentication flows and are not exposed through the Management API.

Account Linking ​

Account linking allows a single user to have multiple authentication identities (connections) consolidated into one user profile. This is useful when:

  • A user signs up with email/password and later wants to link a social login
  • A user has multiple email addresses they want to use with the same account
  • You want to consolidate user accounts that represent the same person

Primary and Secondary Accounts ​

When accounts are linked:

  • One account becomes the primary account - this is the main user profile
  • Other accounts become secondary (linked) accounts - these are attached as additional identities

Updating Linked Accounts ​

You can update properties of linked accounts by specifying the connection parameter in the user update API:

json
PATCH /api/v2/users/{primary_user_id}
{
  "phone_number": "+1234567890",
  "connection": "sms"
}

Supported operations on linked accounts:

  • Update user metadata and app metadata
  • Update email verification status
  • Update phone numbers (for SMS connections)
  • Update passwords (for Username-Password-Authentication connections only)

Important Limitations ​

  • You cannot directly update a linked (secondary) account - all updates must go through the primary account
  • Password updates on linked accounts are only supported for Username-Password-Authentication connections
  • Attempting to update a linked account directly (via its own user_id) will return a 404 error

Querying Linked Accounts ​

When retrieving a primary user, all linked identities are included in the identities array:

json
{
  "user_id": "email|primary-user",
  "email": "[email protected]",
  "identities": [
    {
      "provider": "email",
      "user_id": "primary-user",
      "connection": "email",
      "isSocial": false
    },
    {
      "provider": "sms",
      "user_id": "secondary-user",
      "connection": "sms",
      "isSocial": false,
      "profileData": {
        "phone_number": "+1234567890"
      }
    }
  ]
}

OAuth Grants ​

When a user authorizes a third-party client, AuthHero stores the granted scopes in a grants row keyed by (tenant_id, user_id, client_id, audience). Re-authorizing the same client/audience unions the new scopes into the existing row, so the screen only re-appears when a client asks for something genuinely new.

First-party clients (the default, is_first_party: true) and the OIDC basic scopes (openid, profile, email) never produce a grant — they're exempt from the gate.

Schema (Auth0 wire shape) ​

FieldTypeNotes
idstringnanoid
user_idstringreferences the granting user
clientIDstringreferences the client (Auth0 camelCase oddity)
audiencestring?target audience the grant applies to
scopestring[]unioned set of granted OAuth scopes

List grants ​

http
GET /api/v2/grants?user_id={user_id}
Authorization: Bearer <token with read:grants or auth:read>

Supports user_id, client_id, and audience query filters plus include_totals for the paginated envelope.

When the adapter doesn't implement grants, the endpoint returns an empty array — the feature degrades to "all clients behave as first-party" rather than failing.

Delete grants ​

http
DELETE /api/v2/grants/{id}
DELETE /api/v2/grants?user_id={user_id}

API Reference ​

Dual-licensed: AGPL-3.0-only or commercial license.