Configuration
RESTHeartAll restheart-accounts settings live in restheart.yml across three top-level keys: accountsConfig, oauthConfig, and ermes.
Every section is independent; omitting a section disables the corresponding feature.
Full configuration reference
accountsConfig
accountsConfig:
# MongoDB database where users, teams and oauth_codes are stored.
# Must match mongoRealmAuthenticator.users-db in restheart.yml.
db: 8x5
# Application display name β used in email subjects and bodies.
app-name: "My App"
# JWT access token time-to-live in minutes.
# The key and issuer are sourced automatically from jwtConfigProvider.
jwt-ttl: 15
# Domain used for the JWT authentication cookie (Set-Cookie: Domain=...).
cookie-domain: dev.example.com
# Public URL of the frontend β used to build links in transactional emails.
frontend-url: https://dev.example.com
# URL the browser is redirected to after a successful auto-login
# (email verification, invitation activation, password reset, OAuth callback).
frontend-app-url: https://dev.example.com/app
# Legal policy versions. Activation and registration validate the submitted
# consent versions against these values; bump when T&C or Privacy Policy changes.
terms-version: "1.0"
privacy-version: "1.0"
# Default BCP 47 locale for email templates (used when the user document
# has no "locale" field). Falls back to "en" if omitted.
default-locale: en
# Paths to custom email template HTML files (relative to the RESTHeart
# working directory). Omit any key to use the built-in template.
# See: Email Templates guide.
templates:
verification: etc/email-templates/verification.html
password-reset: etc/email-templates/password-reset.html
invite: etc/email-templates/invite.html
# ββ Membership SPI (9.4.1+) ββββββββββββββββββββββββββββββββββββββββββββββ
# JWT claim name used to carry the active tenant identifier.
# Default: "tenant". Change to e.g. "org" if your domain uses organisations.
# See: Custom Membership Providers.
tenant-claim-name: tenant
# Role name assigned to regular (non-admin) team members.
# Default: "member". Set to "user" if existing ACL rules use that label.
member-role-name: member
# System ACL role assigned to users after email verification or OAuth login.
# New unverified users get roles: ["$unauthenticated"] β they can only access
# public endpoints until verification assigns the real role.
# Default: "user". Override per-tenant via override-accounts-default-role.
default-role: user
# Team role assigned to the user who creates a new team.
# Stored in user.tenants[].role and team.members[].role.
# Default: "owner". Override per-tenant via override-accounts-ownership-role.
ownership-role: owner
# Set to false to disable the built-in membership management endpoints:
# POST /auth/invite, POST /auth/resend-invite,
# GET /auth/tenants, POST /auth/switch-tenant
# Default: true
membership-endpoints-enabled: true
# Additional JWT claims propagated from request attached-parameters to tokens
# issued by accounts endpoints (verify, activate, reset-password, switch-tenant, OAuth).
# Mirrors jwtTokenManager.account-properties-claims: use the same list so that
# all token-issuance paths produce identical JWTs.
# authDb is always included automatically (no need to list it here).
account-properties-claims:
# - srvNode # example: attached-param set by SrvNodeEnricher in multi-tenant deployments
oauthConfig
Omit this section entirely to disable OAuth 2.0 social login.
oauthConfig:
# Master switch. Set to false to disable all OAuth endpoints while keeping
# the configuration in place.
enabled: true
# Base URL of the RESTHeart API instance. Each provider's callback URL is
# constructed as: {api-base-url}/auth/oauth/callback/{provider}
api-base-url: https://api.example.com
# Browser is redirected here after a successful login.
frontend-success-url: https://app.example.com/app
# Browser is redirected here when the OAuth flow fails (e.g. user denied
# consent, invalid state).
frontend-error-url: https://app.example.com/login?error=oauth_error
providers:
google:
enabled: true
client-id: "123β¦.apps.googleusercontent.com"
client-secret: "GOCSPX-β¦"
scope: "openid email profile" # optional β default for google
github:
enabled: true
client-id: "Iv1.β¦"
client-secret: "β¦"
scope: "user:email" # optional β default for github
# Custom provider β requires a matching OAuthProvider plugin in plugins/
# myapp:
# enabled: true
# client-id: "β¦"
# client-secret: "β¦"
# scope: "read:profile"
ermes
Ermes is the SMTP email sender bundled with restheart-accounts.
Omit this section to disable transactional email (registration and invitation flows will not work).
ermes:
enabled: true
# Display name used in the email "From" header.
app-name: "My App"
# From email address.
sender-email: noreply@example.com
# SMTP connection settings.
smtp-hostname: email-smtp.eu-central-1.amazonaws.com
smtp-port: 465 # 465 = SMTPS (implicit TLS); 587 = STARTTLS
smtp-username: AKIAxxxxxxxx
smtp-password: secret
JWT token integration
The JWT access tokens issued by restheart-accounts (after login, verification, activation, password reset, and OAuth callback) are verified by RESTHeart’s own jwtAuthenticationMechanism.
Since RESTHeart v9.5, restheart-accounts reads the JWT signing key and issuer directly from jwtConfigProvider β there is no separate jwt-key or jwt-issuer in accountsConfig.
This eliminates the previous misconfiguration risk where the two keys could diverge, causing 401 Unauthorized errors on auto-login flows.
The only JWT-related setting remaining in accountsConfig is jwt-ttl, which controls how long the auto-login tokens last (independently from the main jwtTokenManager TTL):
# restheart.yml β single source of truth for the JWT key
jwtConfigProvider:
key: your-secret # used by jwtTokenManager, jwtAuthenticationMechanism
# AND restheart-accounts (automatically)
issuer: example.com
accountsConfig:
jwt-ttl: 15 # auto-login token TTL in minutes (accounts-specific)
|
Note
|
If jwt-key or jwt-issuer are still present in your accountsConfig block (from a pre-9.5 configuration), RESTHeart will log a warning and ignore them.
|
Propagating attached-parameters as JWT claims
By default the tokens issued by accounts endpoints (/auth/verify, /auth/activate, /auth/reset-password, /auth/switch-tenant, OAuth callbacks) include:
-
subβ the user’s email -
rolesβ the user’s roles -
authDbβ the MongoDB authentication database (always included automatically; used byJwtAuthDbVerifierin multi-tenant deployments) -
tenant/status(or whichever explicit claims each flow adds)
In multi-tenant or custom deployments, interceptors such as SrvNodeEnricher attach additional parameters to the request before it reaches the service.
To propagate those parameters as JWT claims β so that the resulting token matches what POST /token would issue β list them in account-properties-claims:
accountsConfig:
# Must mirror jwtTokenManager.account-properties-claims so all issuance paths
# produce identical JWTs.
account-properties-claims:
- srvNode # set by SrvNodeEnricher; required by JwtAuthDbVerifier
jwtTokenManager:
account-properties-claims:
- srvNode # keep in sync with accountsConfig.account-properties-claims
authDb is always included automatically from the effective override-users-db value and never needs to appear in the list.
|
Tip
|
Keep accountsConfig.account-properties-claims and jwtTokenManager.account-properties-claims identical.
Any discrepancy means /token and accounts endpoints will issue JWTs with different claims, which can cause subtle authentication failures.
|
Multi-tenancy with AuthDbResolver and TenantConfigInterceptor
To serve multiple tenants from a single restheart-accounts deployment, configure two interceptors at REQUEST_BEFORE_EXCHANGE_INIT:
-
AuthDbResolverβ maps the incoming hostname tooverride-users-dbandoverride-cookie-domain. -
TenantConfigInterceptorβ reads aconfs/{srvId}.accountsdocument from MongoDB and attaches per-tenant app name, frontend URLs, email templates, and OAuth credentials.
Neither interceptor is bundled with restheart-accounts; implement them in your deployment layer.
restheart-accounts automatically detects and uses all override attributes when present.
| Attribute | Source | Overrides |
|---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
email template (inline HTML) |
|
|
email template (inline HTML) |
|
|
email template (inline HTML) |
|
|
|
|
|
|
confs/{srvId}.accounts document schema
The TenantConfigInterceptor reads an accounts sub-document from the existing service-configuration document (e.g. cloud.confs for free/shared nodes, restheart.confs for dedicated nodes).
All fields are optional; absent fields fall back to the node-level static configuration.
{
"_id": "ea820b",
"accounts": {
"app-name": "Customer App",
"frontend-url": "https://app.customer.com",
"frontend-app-url": "https://app.customer.com/app",
"templates": {
"verification": "<html>β¦full HTML stringβ¦</html>",
"password-reset": "<html>β¦</html>",
"invite": "<html>β¦</html>"
},
"oauth": {
"google": {
"enabled": true,
"client-id": "123β¦.apps.googleusercontent.com",
"client-secret": "GOCSPX-β¦"
}
}
}
}
Inline HTML templates stored in MongoDB follow the same format as file-based templates (subject in <title>, i18n via <span lang>, {{variable}} placeholders).
See Email Templates for the full format reference.
|
Tip
|
|
Secrets management (RHO)
Avoid hardcoding secrets in restheart.yml. The JWT key belongs to jwtConfigProvider (not accountsConfig) and is already documented in the JWT configuration section.
Use RESTHeart’s built-in environment variable substitution to inject sensitive values at runtime:
oauthConfig:
providers:
google:
client-secret: $(GOOGLE_CLIENT_SECRET)
github:
client-secret: $(GITHUB_CLIENT_SECRET)
ermes:
smtp-password: $(SMTP_PASSWORD)
Set the corresponding environment variables before starting RESTHeart.
ACL requirements
Each public-facing service registers its own ACL allow rule automatically on startup via the ACLRegistry. No manual ACL entry is needed for these paths. If a service is disabled (or membership-endpoints-enabled: false), its path is not opened.
| Path | Method | Registered by |
|---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
β Disabled when membership-endpoints-enabled: false.
The invite management endpoints are not public. Add the following rules to your ACL (file-based or MongoDB-based) to restrict them to owner role:
# invite and resend-invite require owner or admin
- roles: [owner]
predicate: path('/auth/invite') and method(POST)
priority: 10
- roles: [owner]
predicate: path('/auth/resend-invite') and method(POST)
priority: 10
Minimal configuration (email + password only)
The smallest working setup β no OAuth social login, no custom templates:
accountsConfig:
db: myapp
app-name: "My App"
jwt-ttl: 15
cookie-domain: example.com
frontend-url: https://example.com
frontend-app-url: https://example.com/app
terms-version: "1.0"
privacy-version: "1.0"
ermes:
enabled: true
app-name: "My App"
sender-email: noreply@example.com
smtp-hostname: email-smtp.eu-central-1.amazonaws.com
smtp-port: 465
smtp-username: $(SMTP_USERNAME)
smtp-password: $(SMTP_PASSWORD)
|
Note
|
The JWT key and issuer are inherited from jwtConfigProvider and do not need to appear in accountsConfig.
|