Edit Page

Configuration

RESTHeart

All 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 by JwtAuthDbVerifier in 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 to override-users-db and override-cookie-domain.

  • TenantConfigInterceptor β€” reads a confs/{srvId}.accounts document 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.

Table 1. Override attribute reference
Attribute Source Overrides

override-users-db

AuthDbResolver

accountsConfig.db

override-cookie-domain

AuthDbResolver

accountsConfig.cookie-domain

override-accounts-app-name

TenantConfigInterceptor

accountsConfig.app-name

override-accounts-frontend-url

TenantConfigInterceptor

accountsConfig.frontend-url

override-accounts-frontend-app-url

TenantConfigInterceptor

accountsConfig.frontend-app-url

override-accounts-tmpl-verification

TenantConfigInterceptor

email template (inline HTML)

override-accounts-tmpl-password-reset

TenantConfigInterceptor

email template (inline HTML)

override-accounts-tmpl-invite

TenantConfigInterceptor

email template (inline HTML)

override-accounts-oauth-google-client-id

TenantConfigInterceptor

oauthConfig.providers.google.client-id

override-accounts-oauth-google-client-secret

TenantConfigInterceptor

oauthConfig.providers.google.client-secret

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

AuthDbResolver and TenantConfigInterceptor are both disabled by default. Enable them only on deployments that need multi-tenancy. In single-tenant deployments the plugin uses the static accountsConfig values exclusively.

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

/auth/register

POST

registerService

/auth/verify

GET

emailVerificationService

/auth/forgot-password

POST

forgotPasswordService

/auth/reset-password

PATCH

resetPasswordService

/auth/activate

PATCH

activateService

/auth/invite †

POST

inviteService

/auth/resend-invite †

POST

resendInviteService

/auth/tenants †

GET

getTenantsService

/auth/switch-tenant †

POST

switchTenantService

/auth/oauth/authorize/{provider}

GET

oauthInitiator

/auth/oauth/callback/{provider}

GET

oauthCallback

† 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.