Edit Page

restheart-accounts

RESTHeart Cloud
Note

restheart-accounts is available starting from RESTHeart v9.4, but always use the latest RESTHeart version: the plugin has received substantial additions and security fixes since its introduction (see Security for the /users write restriction added in 9.6.0, among others). v9.4 and v9.5 should be considered deprecated for practical purposes.

restheart-accounts is a RESTHeart plugin that adds application-level account management to any RESTHeart deployment. It covers the full user lifecycle โ€” registration, email verification, team invitations, password reset, and Google OAuth social login โ€” as a set of configurable HTTP endpoints backed by the existing MongoDB user collection (mongoRealmAuthenticator).

The plugin is designed to be a first-class RESTHeart module: all features are opt-in, configured exclusively via restheart.yml, and produce standard JWT tokens that integrate transparently with the existing RESTHeart security pipeline.

flowchart LR
  subgraph Clients
    B[Browser / Mobile]
  end

  subgraph RA[restheart-accounts]
    direction TB
    EP["Endpoints\n/auth/register  /auth/verify\n/auth/forgot-password  /auth/reset-password\n/auth/invite  /auth/invitations  /auth/activate\n/auth/teams  /auth/team  /auth/team/members  /auth/switch-team\n/auth/profile  /auth/change-password\n/auth/oauth/authorize  /auth/oauth/callback"]
    MPS[MembershipProvider SPI]
    EP --> MPS
  end

  subgraph Storage
    M[(MongoDB\nusers ยท acl\nauth_invitations\noauth_codes)]
    E[Email\nSMTP / emails module]
  end

  P[OAuth Provider\nGoogle ยท GitHub]

  B -- HTTP + JWT --> RA
  RA --> M
  RA --> E
  RA -- OAuth flow --> P

Endpoints

Method URI Auth Description

POST

/auth/register

public

Signup with email + password; creates user and team

GET

/auth/verify

public

Verify email via token link; auto-login via cookie or URL fragment (delivery param)

POST

/auth/forgot-password

public

Request password reset link, or re-send the verification email if the account isn’t verified yet (always 202)

PATCH

/auth/reset-password

public

Apply reset token; auto-login

POST

/auth/invite

owner / admin

Invite a user to the caller’s team โ€ 

PATCH

/auth/activate

public

Accept invitation, set password; auto-login

POST

/auth/resend-invite

owner / admin

Re-send an expired invitation (email in request body) โ€ 

GET

/auth/invitations

owner / admin

List pending (non-expired) invitations for the caller’s active team โ€ 

GET

/auth/teams

authenticated

List the caller’s team memberships (includes description when non-null) โ€ 

POST

/auth/teams

authenticated

Create an additional team for the caller; becomes the newly active team, reissues JWT cookie โ€ 

GET

/auth/team/members

authenticated

List the caller’s active team’s members (name, email, role, joinedAt) โ€ 

PATCH

/auth/team

owner

Rename/edit the caller’s active team (name, description) โ€ 

DELETE

/auth/team

owner

Delete the caller’s active team, only if it has no other members (409 otherwise) โ€ 

POST

/auth/switch-team

authenticated

Switch active team; reissues JWT cookie โ€ 

PATCH

/auth/profile

authenticated

Self-service update of the caller’s own profile (firstName, lastName)

PATCH

/auth/change-password

authenticated

In-session password change (current password โ†’ new password); also lets OAuth-only accounts set their first password, with no current one to confirm

GET

/auth/oauth/authorize/{provider}

public

Redirect browser to the OAuth provider’s consent screen

GET

/auth/oauth/callback/{provider}

public

OAuth callback: exchange code, upsert user, set JWT cookie

โ€  Disabled when accountsConfig.membership-endpoints-enabled: false. See Custom Membership Providers for details.

/users Access

Caution
Since RESTHeart 9.6.0.

Once accountsInitializer is enabled, management of the users collection passes to restheart-accounts: the generic MongoDB REST resource at /users is restricted to self-service profile.* edits, regardless of what ACL the application defines.

  • PUT and POST are always rejected โ€” creating or fully replacing a user document must go through a restheart-accounts endpoint (/auth/register, /auth/verify, /auth/activate, /auth/accept-invite, the OAuth callback, …​), never the generic REST resource.

  • PATCH is only permitted if every field it touches is under profile.*. This is enforced regardless of how the field is expressed โ€” dot notation (profile.name) or a MongoDB update operator ($set, $push, $addToSet, …​) โ€” so {"$set": {"teams.0.role": "owner"}} is rejected exactly like {"teams": […​]}.

This closes a privilege-escalation path: an ACL commonly grants an authenticated user permission to PATCH their own /users/{email} document for profile self-editing (name, avatar, …​). Without this restriction, that same permission would let the user rewrite any field on their own document โ€” roles, team/teams, or a directly-set password โ€” e.g. promoting themselves to owner of a team. The restriction is enforced unconditionally, for every application built on restheart-accounts, independent of how permissive its own ACL is โ€” and it doesn’t affect restheart-accounts itself, since every endpoint that legitimately needs to set roles/teams/password/tokens writes to MongoDB directly via the driver, not through the REST resource.

Exceptions are configured via accountsConfig.users-unrestricted-roles โ€” a list of roles exempt from the restriction (both the PUT/POST block and the profile.* limit on PATCH), useful for an internal admin console that manages roles/teams directly:

accountsConfig:
  users-unrestricted-roles: [admin]

Leave it unset (the default) to apply the restriction to every caller, with no exceptions. In multi-tenant deployments this can also be overridden per team โ€” see override-accounts-users-unrestricted-roles in the table below.

See Accounts / Security for the full technical explanation.

Multi-tenancy

restheart-accounts supports multi-team deployments without any custom code in the plugin itself. All services check for request attributes injected by an upstream interceptor (such as AuthDbResolver or TeamConfigInterceptor) and use them in place of the static configuration values.

See Multi-tenancy for the per-request override mechanism and Custom Membership Providers for replacing the built-in team storage model.

Table 1. Full list of override request attributes
Request attribute Overrides Effect

override-users-db

accountsConfig.db

Users and teams are read from and written to this database

override-cookie-domain

accountsConfig.cookie-domain

The JWT authentication cookie is scoped to this domain

override-accounts-app-name

accountsConfig.app-name

Application name used in email subjects and bodies

override-accounts-frontend-url

accountsConfig.frontend-url

Base URL used in transactional email links

override-accounts-frontend-app-url

accountsConfig.frontend-app-url

Redirect target after successful auto-login

override-accounts-tmpl-verification

file path / built-in template

Inline HTML string for the email-verification template (stored in MongoDB)

override-accounts-tmpl-password-reset

file path / built-in template

Inline HTML string for the password-reset template

override-accounts-tmpl-invite

file path / built-in template

Inline HTML string for the invitation template

override-accounts-oauth-google-client-id

oauthConfig.providers.google.client-id

Per-team Google OAuth client ID

override-accounts-oauth-google-client-secret

oauthConfig.providers.google.client-secret

Per-team Google OAuth client secret

override-accounts-users-unrestricted-roles

accountsConfig.users-unrestricted-roles

Roles exempt from the /users self-service write restriction (since 9.6.0)

override-accounts-signup-mgmt-enabled

(none โ€” always active by default)

When false, skips the /users self-service write restriction entirely for the tenant, for every caller (since 9.6.0). Must be attached before authentication.

When an attribute is absent the plugin falls back to the corresponding static value in accountsConfig / oauthConfig.

A typical multi-team setup (e.g. restheart-cloud) has two interceptors running at REQUEST_BEFORE_EXCHANGE_INIT:

  • AuthDbResolver โ€” maps the incoming hostname to the correct override-users-db and override-cookie-domain.

  • TeamConfigInterceptor โ€” reads the confs/{srvId}.accounts MongoDB document and attaches the remaining override attributes (app-name, frontend-url, per-team templates, per-team OAuth credentials).

Neither interceptor is part of restheart-accounts; they belong to the deployment layer (e.g. restheart-cloud-server). No configuration changes to the plugin are needed per team.

OAuth & MCP

restheart-accounts implements social login via the /auth/oauth/* endpoints, with built-in support for Google and GitHub and a Java SPI for registering custom providers. The plugin exchanges the OAuth authorization code (using ScribeJava) for user information, creates or updates the user document in MongoDB, and issues a RESTHeart JWT cookie โ€” no custom OAuth logic required in the client.

This is distinct from RESTHeart’s built-in OAuth 2.1 authorization server, which is part of RESTHeart core and exposes standard endpoints (/authorize, /token, /introspect, etc.) intended for tool and client authentication โ€” primarily for MCP (Model Context Protocol) integrations. The two systems serve different purposes and operate completely independently.

See OAuth 2.0 Social Login for setup instructions for all providers, including the custom provider SPI.

Dependencies

  • RESTHeart โ‰ฅ 9.3 with mongoRealmAuthenticator and jwtTokenManager enabled.

  • An SMTP provider configured via the emails section (required for all email-based flows).

  • OAuth provider credentials (optional โ€” required only for the providers enabled under oauthConfig.providers).