Skip to content

Configuration

A key concept of SympAuthy is to allow you to deploy a fully configured instance of it without requiring you to connect to an interface. Therefore, all the configurations of SympAuthy must be text-based and deployed alongside it.

For this matter, SympAuthy relies on the configuration mechanism of Micronaut.

Everything is configurable through the use of:

  • YAML or JSON configuration files.
  • environment variables.
  • parameters passed to the binary.

Micronaut Environments

SympAuthy uses Micronaut Environments to allow you to use well-crafted configurations out-of-the-box.

  • default: Configure every configuration keys listed below with the value indicated in the Default column of the table. It does not enable any feature that is considered unsecure.
  • by-mail: Allow the end-user to sign in/sign-up using a login/password with the login being an email address.
  • Well-known providers: Pre-built configurations for common third-party providers (Google, Discord, etc.). Activating one by its environment name automatically configures the OAuth2 URLs, scopes, and claim mappings for that provider.

The micronaut environments you are using can be set using the MICRONAUT_ENVIRONMENTS environment variable. ex MICRONAUT_ENVIRONMENTS=default,by-mail,google

Configuration keys

This section describes all the configuration key allowing to configure your instance of SympAuthy.

The configuration key in the sections and in the tables are sorted by alphanumerical order.

Micronaut

Since SympAuthy is constructed using the Micronaut framework, it shares the configuration keys of all Micronaut-based applications to configure some basic features. The table below provides examples of commonly used keys:

KeyTypeDescriptionRequired
Default
micronaut.server.portintTCP port the server will be listening to.NO
8080

The full list is available in the Micronaut documentation.

r2dbc

This authorization server accesses its database through Micronaut R2DBC.

The database must exist before starting SympAuthy. Only the schema (tables, indexes, etc.) is created automatically on first startup.

r2dbc.datasources.default

KeyTypeDescriptionRequired
Default
urlstringR2DBC connection URL to the database.YES
usernamestringUsername used to authenticate to the database.YES
passwordstringPassword used to authenticate to the database.NO

Supported databases

PostgreSQL

yaml
r2dbc:
  datasources:
    default:
      url: r2dbc:postgresql://<host>:<port>/<database>
      username: <username>
      password: <password>

H2 (in-memory, for development only)

yaml
r2dbc:
  datasources:
    default:
      url: r2dbc:h2:mem:///sympauthy

javamail

This authorization server can email a user through the use of Micronaut Email.

The SMTP client implementation was chosen because it can be easily integrated with the most commonly used mailing solutions on the market:

KeyTypeDescriptionRequired
Default
enabledbooleanSet to true to enable sending emails. If mails are enable but the configuration is missing, it will fail to start with the following message: JavaMail configuration does not contain any properties.NO
authenticationobjectContains the username and the password to authenticate to the SMTP server.NO
propertiesobjectConfiguration of the SMTP library using its properties.YES

Example:

yaml
javamail:
  enabled: true
  authentication:
    username: username
    password: password
  properties:
    mail:
      from: noreply@example.com
      smtp:
        host: ssl.smtp.example.com
        port: 465
        ssl:
          enable: true

javamail.authentication

KeyTypeDescriptionRequired
Default
<id>stringUniq identifier of the client.YES
secretstringA secret shared between the client and the authorization server.YES
allowed-grant-typesarray of stringList of OAuth2 grant types this client is allowed to use. Supported values: authorization_code, refresh_token, client_credentials.YES
allowed-redirect-urisarray of stringA list of URIs where the client is allowed to ask the redirection of the end-user at the end of the OAuth2 authorize grant flow. Required when authorization_code is in allowed-grant-types.Conditional

advanced

This section holds configuration that will change the general behavior of the server.

KeyTypeDescriptionRequired
Default
jwtobjectYES
user-merging-strategystringDeprecated — replaced by auth.user-merging-enabled.YES
by-mail
keys-generation-strategystringYES
autoincrement
validation-codeobjectSee advanced.validation-code.YES

advanced.hash

KeyTypeDescriptionRequired
Default
block-sizeintYES
8
cost-parameterintYES
16384
key-lengthintNumber of bytes generated as output of the hashing algorithm.YES
32
parallelization-parameterintYES
1
salt-lengthintNumber of random bytes to generate and then use as a salt for the hashing algorithm.YES
256

advanced.jwt

KeyTypeDescriptionRequired
Default
access-algstringAlgorithm used to sign access tokens. The algorithm MUST be asymmetric and support a public key. Access tokens are signed with a dedicated key, separate from ID tokens per RFC 9068.YES
rs256
public-algstringAlgorithm used to sign ID tokens and other keys shared publicly. The algorithm MUST be asymmetric and support a public key.YES
rs256
private-algstringAlgorithm used to encrypt internal keys. The algorithm only have to support public key.YES
rs256

advanced.validation-code

KeyTypeDescriptionRequired
Default
expirationdurationDuration, after the validation code has been generated, where the server will accept it.YES
10m
lengthintNumber of digit expected in validation code generate by this authorization server.YES
6
resend-delaydurationDuration the end-user has to wait before being able to request a new validation code to be sent.YES
1m

auth

KeyTypeDescriptionRequired
Default
issuerstringThe public URL of this authorization server, embedded as the iss claim in every JWT token it issues. Clients use it to verify that a token was issued by the expected server and to discover the OpenID Connect configuration at <issuer>/.well-known/openid-configuration.YES
<urls.root>
audiencestringAudience of the JWT tokens issued for end-user authentication (ex. OAuth2 access and refresh tokens). Required by RFC 9068 in access tokens.NO
<urls.root>
identifier-claimsarray of stringList of claim identifiers that uniquely identify a person. These claims are used as the login identifier for password authentication and, when user-merging-enabled is true, as the key for merging accounts across authentication methods.NO
[]
user-merging-enabledbooleanWhen true, accounts that share the same value for any configured identifier-claims are automatically merged across authentication methods (password, third-party providers). When false, each authentication method creates a separate account.NO
false
authorization-codeobjectConfiguration for the authorization code grant flow. See auth.authorization-code for more details.NO
tokenobjectConfiguration related to authentication tokens issued by this app. See auth.token for more details.NO

auth.authorization-code

KeyTypeDescriptionRequired
Default
expirationdurationMaximum duration an authorization attempt is valid before it expires. The end-user must complete the entire authorization flow (sign-in, claims collection, MFA, etc.) within this time.YES
30m

auth.by-password

KeyTypeDescriptionRequired
Default
enabledbooleanEnable password-based authentication.NO
false

auth.token

KeyTypeDescriptionRequired
Default
access-expirationdurationAmount of time the end-user can be considered authenticated after the access token has been issued.YES
1h
dpop-requiredbooleanWhen true, all token requests must include a DPoP proof. When false, DPoP is opt-in: clients may send a proof to receive a sender-constrained token, or omit it to receive a bearer token.NO
false
refresh-enabledbooleanIf set to true, this app will issue refresh tokens that can be used to obtain a new access token without the end-user having to go through the authentication flow.YES
true
refresh-expirationdurationAmount of time the refresh token can be used to obtain an access token after it has been issued. The refresh token will never expire if this key is not present.NO

claims.<id>

This section holds the configuration of claim that can be collected by this authorization server.

There are two types of claims that can be collected by this authorization server:

Common for both claim types

KeyTypeDescriptionRequired
Default
allowed-valuesarrayList of possible values an user can provide for this claim. If not specified or null, all values will be accepted by the authorization server.
Note: Changing this configuration will not change the value collected for existing user.
NO
null
enabledbooleanEnable the collection of this claim for end-users. If disabled, the claim will never be stored by this authorization server even if it is made available by a client or a provider. In case this config is changed, it is up to the operator of the authorization server to clear the claim that have been already collected.NO
false
requiredbooleanThe end-user must provide a value for this claim before being allowed to complete an authorization flow.NO
false

OpenID Connect claims

KeyTypeDescriptionRequired
Default
<id>stringOne of the OpenID defined claims.YES

Custom claims

KeyTypeDescriptionRequired
Default
<id>stringA string identifying this claim.YES
typestringThe type of data the user is expected to input for this claim.YES

claims.<id>

The identifier must not contain a dot character.

claims.<id>.type

clients.<id>

This section holds the configuration of all clients that will be authorized to authenticate their users with this authorization server.

KeyTypeDescriptionRequired
Default
<id>stringUniq identifier of the client.YES
<authorizationFlow>stringThe identifier of the authorization flow to use for this client. See authorization flows for more details.YES
publicbooleanWhen true, the client is a public client that does not require a secret. Public clients must use PKCE and cannot use the client credentials grant.NO
false
secretstringSecret shared between the client and the authorization server. Required for confidential clients (public: false). Must be omitted for public clients.Conditional
allowed-grant-typesarray of stringList of OAuth2 grant types this client is allowed to use. Supported values: authorization_code, refresh_token, client_credentials. See this section for more details.YES
allowed-scopesarray of stringList of scopes the client is allowed to request. Any scope outside this list will be filtered out by this authorization server and will not be granted.
If not set or empty, all scopes are allowed.
NO
default-scopesarray of stringList of scopes that will be requested if the scope parameter is left when calling the authorize endpoint.NO
urismap of stringNamed URIs for this client, usable as ${client.uris.<key>} templates in allowed-redirect-uris. Useful for defining base URLs once and referencing them in multiple redirect URIs.NO
allowed-redirect-urisarray of stringA list of URIs where the client is allowed to ask the redirection of the end-user at the end of the OAuth2 authorize grant flow. See this section for more details.Conditional

clients.<id>.allowed-grant-types

Every client must declare at least one grant type. The server rejects any client configuration without allowed-grant-types at startup.

Supported values:

ValueDescription
authorization_codeEnables the authorization code flow. The client can redirect end-users to the authorize endpoint.
refresh_tokenAllows the client to exchange a refresh token for new tokens. Requires authorization_code to also be present.
client_credentialsAllows the client to authenticate directly using its own credentials, without an end-user. Only available to confidential clients (public: false).

Constraints:

  • refresh_token cannot be used without authorization_code. The server rejects this combination at startup.
  • When authorization_code is not in the allowed grant types, the authorize endpoint rejects the client and allowed-redirect-uris must not be configured.
  • When refresh_token is not in the allowed grant types, no refresh token is issued in the authorization code flow response.

clients.<id>.allowed-redirect-uris

Clients that support the authorization_code grant type must declare at least one redirect URI. The server rejects the configuration at startup if allowed-redirect-uris is missing when authorization_code is allowed, or if allowed-redirect-uris is present when authorization_code is not allowed.

Exact string matching

As required by OAuth 2.1, redirect URIs are compared using exact string matching — no prefix matching, pattern matching, or normalization is applied.

For native applications using loopback redirects, the port component is ignored when the host is 127.0.0.1 or [::1] and the scheme is http or https, as recommended by RFC 8252. This exception does not apply to localhost or to custom-scheme URIs.

Template support

Redirect URIs support ${...} placeholders that are resolved at startup:

TemplateDescription
${urls.root}The root URL of the authorization server.
${client.uris.<key>}A named URI defined in the client's uris map (see above).

Example configuration:

yaml
clients:
  admin:
    uris:
      app: https://admin.example.com
    allowed-redirect-uris:
      - "${urls.root}/admin/callback"
      - "${client.uris.app}/callback"

  mobile:
    uris:
      app: myapp://
    allowed-redirect-uris:
      - "${client.uris.app}callback"

features

This section holds configuration related to features that can be enabled or disabled.

KeyTypeDescriptionRequired
Default
allow-access-to-client-without-scopebooleanAllow the end-user to be redirected back to the client application even when none of the requested authorization scopes have been grantedNO
false
email-validationbooleanEnforce the validation of the end-user's emails. A SMTP must be configured (see javamail) to enable this feature.NO
false
grant-unhandled-scopesboolean⚠️ UNSAFE - DEVELOPMENT ONLY. Automatically grant ALL grantable scopes requested by the client that are not explicitly granted nor declined by any scope granting rule.
When enabled: Any grantable scope not explicitly granted nor declined is automatically granted.
When disabled: Grantable scopes not explicitly granted are rejected (secure default).
This feature only applies to grantable scopes. Consentable scopes always require end-user consent and client scopes have their own granting rules.
To know more about scope granting rules, see this documentation.
NO
false

mfa

This section controls multi-factor authentication (MFA). MFA adds an extra verification step after the user has authenticated with their primary method (password or third-party provider).

KeyTypeDescriptionRequired
Default
requiredbooleanWhen true, every user must complete MFA before the flow can proceed. When false, users may skip MFA.NO
false
totp.enabledbooleanEnable TOTP (Time-based One-Time Password, RFC 6238) as an MFA method.NO
false

When mfa.totp.enabled is true, the corresponding flow URLs (mfa, mfa-totp-enroll, mfa-totp-challenge) must be configured in the flows.<id> section. SympAuthy validates this at startup and refuses to start if any required URL is missing.

flows.<id>

This configuration holds the URL where the end-user will be redirected during its authentication. Sympathy already includes a complete authentication flow.

Web

The flow may be completely customized and served by a completely different server than the authorization server.

SympAuthy derives the allowed CORS origins for the Flow API (/api/v1/flow/**) from the URIs declared here. For each URI, the origin (scheme://host:port) is extracted and whitelisted. Requests from any other origin are refused. See the Security documentation for details.

KeyTypeDescriptionRequired
Default
sign-inuriThe URL where the end-user will be enabled to sign-in using any supported methods (password or third party providers)YES
/sign-in
mfauriThe URL of the MFA router/method-selection page.NO
mfa-totp-enrolluriThe URL of the TOTP enrollment page.NO
mfa-totp-challengeuriThe URL of the TOTP challenge page.NO
erroruriThe URL where the end-user will be redirected if an error occurs during the authentication.YES
/error

The mfa, mfa-totp-enroll, and mfa-totp-challenge URLs are required when mfa.totp.enabled is true. SympAuthy validates this at startup and fails fast if they are missing.

providers.<id>

This section holds the configuration of a third-party provider (identified by id) the end-user can go through to authenticate itself.

KeyTypeDescriptionRequired
Default
idstringIdentifier of the provider. ex. googleYES
namestringName of the provider that will be displayed to users by UI. ex. GoogleYES
oauth2objectInfo to initiate an OAuth2 authorization code grant flow with the provider. See OAuth2 keys for more details.NO
oidcobjectInfo to initiate an OpenID Connect flow with the provider. See OIDC keys for more details.NO
uiobjectNO
user-infoobjectEndpoint called to obtain end-user info from the provider. See user info keys for more details.- OAuth2: YES
- OpenID Connect: NO

Each provider must have exactly one of oauth2 or oidc configured — not both. OIDC providers use OpenID Connect Discovery to automatically resolve endpoints from the issuer URL. This means you do not need to specify endpoint URLs or claim mappings manually.

providers.<id>.oidc

KeyTypeDescriptionRequired
Default
issuerurlThe OpenID Connect issuer URL. SympAuthy will fetch the discovery document at {issuer}/.well-known/openid-configuration to resolve all endpoints.YES
client-idstringAn identifier provided by the provider to identify authentication initiated by this authorization server.YES
client-secretstringA secret provided by the provider. It must only be shared between the provider and this authorization server.YES
scopesstring[]Scopes requested to the provider. The openid scope is always included automatically.NO
[openid]
userinfo-enabledbooleanWhether to also call the provider's UserInfo endpoint to fetch additional claims. When false, claims are extracted from the ID token only.NO
false

The discovery document is fetched at startup. If the issuer URL is invalid or unreachable, SympAuthy will fail fast with a clear error message.

When userinfo-enabled is false (the default), SympAuthy extracts user claims directly from the ID token returned by the provider. This is sufficient for most providers (Google, Microsoft, Auth0, etc.) and avoids an extra HTTP call.

providers.<id>.oauth2

KeyTypeDescriptionRequired
Default
client-idstringAn identifier provided by the provider to identify authentication initiated by this authorization server.YES
client-secretstringA secret provided by the provider. It must only be shared between the provider and this authorization server.YES
scopesstringScope requested to the provider to access the info of the user.YES
authorization-urlurlThe OAuth2 authorize url where to redirect the end-user to initiate an authentication with this provider.YES
token-urlurlThe OAuth2 token endpoint this authorization server should contact to obtain an access tokensYES
token-auth-methodstringHow this authorization server should pass the client id and the client secret to the token endpoint.YES

providers.<id>.user-info

KeyTypeDescriptionRequired
Default
urlurlEndpoint URL to get end-user information from the provider.YES
pathsobjectObject containing JSONPath to use to extract the end-user info from the response of the UserInfo endpoint of the provider. The key is one of the OpenID defined claims. The value is the JSONPath used to extract the claim value from the response.YES

scopes.<id>

KeyTypeDescriptionRequired
Default
enabledbooleanEnable the scope.NO
false
typestringThe scope type. Either consentable or grantable. Custom client scopes are not supported.NO
grantable

urls

KeyTypeDescriptionRequired
Default
rootabsolute urlThe url at which the end-user can access the root of the application.YES
flowobjectThe urls where the end-user will be redirected during authentication. See urls.flowYES
Internal flow

rules

This section holds the configuration of scope granting rules.

KeyTypeDescriptionRequired
Default
userarray of objectScope granting rules evaluated during authorization_code flows to grant or deny grantable scopes. Expressions evaluate user claims using CLAIM(...) and CLAIM_IS_VERIFIED(...).NO
clientarray of objectScope granting rules evaluated during client_credentials flows to grant or deny client scopes. Expressions evaluate client attributes using CLIENT(...).NO

rules.user / rules.client

Both user and client arrays share the same rule structure:

KeyTypeDescriptionRequired
Default
scopesarray of stringScopes affected by this rule. Only requested scopes that appear in this list are granted or denied.YES
behaviorstringgrant to include the scopes in tokens, deny to exclude them.YES
orderintPrecedence when multiple rules affect the same scope. A matched rule with greater order overrides matched rules of lower order. A matched deny rule always wins over grant rules of same or lower order.NO
0
expressionsarray of stringConditions that must all evaluate to true for the rule to match.YES

Example:

yaml
rules:
  user:
    - scopes:
        - admin:config:read
        - admin:users:read
        - admin:users:write
      behavior: grant
      order: 0
      expressions:
        - CLAIM("email") = "admin@example.com" && CLAIM_IS_VERIFIED("email")
  client:
    - scopes:
        - users:claims:write
      behavior: grant
      order: 0
      expressions:
        - CLIENT("name") = "backoffice"