restheart-accounts
RESTHeart Cloud|
Note
|
|
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 |
|---|---|---|---|
|
|
public |
Signup with email + password; creates user and team |
|
|
public |
Verify email via token link; auto-login via cookie or URL fragment ( |
|
|
public |
Request password reset link, or re-send the verification email if the account isn’t verified yet (always 202) |
|
|
public |
Apply reset token; auto-login |
|
|
owner / admin |
Invite a user to the caller’s team โ |
|
|
public |
Accept invitation, set password; auto-login |
|
|
owner / admin |
Re-send an expired invitation (email in request body) โ |
|
|
owner / admin |
List pending (non-expired) invitations for the caller’s active team โ |
|
|
authenticated |
List the caller’s team memberships (includes |
|
|
authenticated |
Create an additional team for the caller; becomes the newly active team, reissues JWT cookie โ |
|
|
authenticated |
List the caller’s active team’s members (name, email, role, joinedAt) โ |
|
|
owner |
Rename/edit the caller’s active team (name, description) โ |
|
|
owner |
Delete the caller’s active team, only if it has no other members ( |
|
|
authenticated |
Switch active team; reissues JWT cookie โ |
|
|
authenticated |
Self-service update of the caller’s own profile ( |
|
|
authenticated |
In-session password change (current password โ new password); also lets OAuth-only accounts set their first password, with no current one to confirm |
|
|
public |
Redirect browser to the OAuth provider’s consent screen |
|
|
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.
-
PUTandPOSTare always rejected โ creating or fully replacing a user document must go through arestheart-accountsendpoint (/auth/register,/auth/verify,/auth/activate,/auth/accept-invite, the OAuth callback, …), never the generic REST resource. -
PATCHis only permitted if every field it touches is underprofile.*. 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.
| Request attribute | Overrides | Effect |
|---|---|---|
|
|
Users and teams are read from and written to this database |
|
|
The JWT authentication cookie is scoped to this domain |
|
|
Application name used in email subjects and bodies |
|
|
Base URL used in transactional email links |
|
|
Redirect target after successful auto-login |
|
file path / built-in template |
Inline HTML string for the email-verification template (stored in MongoDB) |
|
file path / built-in template |
Inline HTML string for the password-reset template |
|
file path / built-in template |
Inline HTML string for the invitation template |
|
|
Per-team Google OAuth client ID |
|
|
Per-team Google OAuth client secret |
|
|
Roles exempt from the |
|
(none โ always active by default) |
When |
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 correctoverride-users-dbandoverride-cookie-domain. -
TeamConfigInterceptorโ reads theconfs/{srvId}.accountsMongoDB 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
mongoRealmAuthenticatorandjwtTokenManagerenabled. -
An SMTP provider configured via the
emailssection (required for all email-based flows). -
OAuth provider credentials (optional โ required only for the providers enabled under
oauthConfig.providers).