Breaking
Technically, this is not a breaking change, but it might be for you. The config parser now has an additional validation for left-over, unknown keys after parsing has finished. If any data is left, Rauthy will panic. This makes sure you cannot have typos or data in your config that does nothing at all. This means this might be a somewhat "breaking" change if you have invalid or additional data in your config. Just be prepared to adjust your config when you update.
Security
In some scenarios, when you knew the internal User ID of another user, and you had a similar Password / MFA configuration, it was possible to get mixed session states during Webauthn Ceremony Finish. It was e.g. possible to reset the "last login" timestamp or to trigger a "Login from new location" message for another user.
Changes
Delegated Group Admins
You can now delegate user management to non-admins via group-scoped roles. A role named rauthy_admin:<group> makes its holders a group admin for the matching group(s): an exact match by default, a trailing * for a prefix glob, and rauthy_admin:* for all groups.
A group admin can manage users that are members of a group it manages (create, edit profile, toggle enabled, manage in-scope group memberships, reset MFA, reset or set a password, manage the profile picture, view / invalidate sessions, and send a bulk E-Mail scoped to one of its managed groups) and gets a read-only view of Sessions, Events and the Blacklist for debugging. It can never modify roles, delete users, send unscoped bulk E-Mails, manage other admins, or touch any non-user administration. This is non-breaking unless you already use a custom role starting with rauthy_admin:; such roles are logged on startup.
Custom Claims on client_credentials Tokens
A client can now carry admin-defined custom claims. You can set a JSON object on a Client in the Admin UI (or via the management API), which is emitted into the access token of the client_credentials flow. This lets machine clients carry self-describing claims (workload identity, tenant id, deployment profile, ...) without the resource server having to look anything up
by client_id.
By default, the claims are nested under the custom claim; an opt-in claims_at_root flag emits them at the token root instead (a collision with a reserved claim fails token issuance). The value must be a JSON object and is capped at 1024 serialized characters. Dynamic and ephemeral clients cannot set their own claims.
Resource Indicators (RFC 8707)
Rauthy now supports RFC 8707 resource indicators. Clients may send a resource parameter on the authorization and token requests (for the authorization_code, client_credentials and refresh_token grants) to request an audience-restricted access token. The requested resource is validated against a new per-client allowed_resources allow-list (empty means deny, returning invalid_target), and a second new per-client field default_aud lets you always add fixed audiences to a client's tokens without a request parameter, e.g. for clients that cannot send a resource.
Ephemeral clients deny resource requests by default unless ephemeral_clients.danger_allow_unvalidated_resource is enabled or the client document declares its own allowed_resources.
[ephemeral_clients]
# RFC 8707: when an ephemeral client document declares no `allowed_resources`,
# a requested `resource` is rejected by default. Setting this to `true` lets such
# clients request any resource indicator.
#
# CAUTION: only enable this if you know exactly what you are doing and have a good
# reason. It can lead to an easy privilege escalation, because an ephemeral client
# could then mint tokens for an arbitrary audience.
#
# default: false
# overwritten by: EPHEMERAL_CLIENTS_DANGER_ALLOW_UNVALIDATED_RESOURCE
danger_allow_unvalidated_resource = falseAs part of this, the aud claim is now emitted as a JSON array when a token carries two or more audiences, and stays a single string otherwise. This also fixes the solid_aud case for Solid-OIDC ephemeral clients, which previously emitted a string that merely looked like an array.
Secrets from file
You now have a 3rd option to provide secrets. The first is to inline them in the config, which makes the config itself a secret. The 2nd is to provide them as ENV vars, which you should avoid if possible, but sometimes it's the only way. The new option now is from an additional secrets file.
By default, Rauthy will look for a ./secrets.toml. You can overwrite the path via CLI when serveing with the -s, --secrets-file <SECRETS_FILE> option.
You can only put real secrets inside this file. Anything additional will trigger an error. By default, these values are ignored unless you explicitly configure them to be read from this file. To do so, instead of providing a secrets inside the config directly, you can set the values to
"$SECRETS"
This value is case-sensitive. If set to any of the secrets, the config parser expects the value to exist in the secrets toml file.
As mentioned already, this file must have the exact same sections and variable names as the secret in the main config. For instance, if you have database.pg_password in the config, and you set the value to "$SECRETS", you must provide a database.pg_password in the secrets toml.
You can optionally read the following secrets in this way:
[cluster]
secret_raft = ''
secret_api = ''
s3_key = ''
s3_secret = ''
password_dashboard = ''
[database]
pg_user = ''
pg_password = ''
[dynamic_clients]
reg_token = ''
[email]
smtp_username = ''
smtp_password = ''
xoauth_client_id = ''
xoauth_client_secret = ''
[encryption]
keys = ['']
key_active = ''
[events]
matrix_user_id = ''
matrix_access_token = ''
matrix_user_password = ''
slack_webhook = ''
[geolocation]
maxmind_account_id = ''
maxmind_license_key = ''
[user_pictures]
s3_key = ''
s3_secret = ''The
encryption.keysis an exception here. The parser expects an array instead of a single String. You can read them from secrets with by setting:keys = ['$SECRETS']
PAM User custom home
You can now set a custom home directory for PAM users. To make this work end-to-end, an update of the rauthy-pam-nss service is necessary as well.
API Keys Advanced Bootstrap
API Keys can now be bootstrapped during advanced bootstrapping from JSON files.
Advanced Bootstrapping
Secrets can now be auto-generated during bootstrapping from files. They are then saved inside an encrypted container on disk, which you can read via the Rauthy CLI afterwards. For detailed information, check the book.
API Keys can manage other API Keys
Even though not being recommended, you can now allow an API key to manage other API keys.
Pattern hint for preferred_username
You can now specify a custom pattern hint for the pattern validation in the UI for the Preferred Username.
[user_values.preferred_username]
# Configure a hint that will be shown to the user on pattern
# mismatch.
#
# default: not set
pattern_hint = 'Linux-compatible Username'Stricter Client ID validation
Client IDs for manually managed clients are now validated against the stricter pattern ^[a-zA-Z0-9._\-]{2,256}$, which matches the existing Admin UI restriction. This applies when creating a client via the API and when bootstrapping clients from JSON files. Ephemeral clients are unaffected and may still use a full URI as their ID.
Previously, the backend accepted URI-shaped IDs on these paths, even though such a client cannot be managed in the Admin UI and behaves completely differently depending on whether ephemeral clients are enabled. Existing clients with such an ID keep working and can still be updated, since the ID for an update is taken from the URL path; only creating or bootstrapping a new client with such an ID is now rejected.
As part of this, the redundant id field was removed from the client update request body. It was a leftover from an older API version: on update the ID is always taken from the URL path and could never be changed, so the field had no effect, and any id still sent in the body is now ignored.
Validate Config
The CLI can now validate an existing Rauthy Config:
./rauthy validate-config -p config.tomlHiqlite v0.14.0
Hiqlite was updated to v0.14.0.
You can now rate-limit all Raft write actions. These are things like cache PUT or e.g. execute queries. This limit does not affect read actions, since they are local and do not travel through the network. With this rate-limiting, if tuned properly for your deployment, you can guarantee that you never saturate your disk, and therefore can never get in a situation where you overwhelm the cluster, no matter how high requests might spike.
Just as a very rough guideline: When you only write tiny queries that INSERT 3 columns per row, and you limit the Raft to 50.000 requests / s, your disk already writes 350+ MB/s. How you want to tune this value depends a lot on how much your server can handle and how expensive your queries are. It's impossible to provide a reasonable default value here.
Each client has its own rate-limiter. This is crucial. If the leader enforced it, all limited requests would need to travel through the network only for getting limited. This means if you have a traffic spike that your deployment cannot handle, it would still flood the network. Instead, each client enforces this locally BEFORE sending out any network requests. At the same time, this means if you limit to e.g. 100 RPS while having a 3-node cluster, it will effectively mean ~300 RPS for the whole cluster (assuming even load balancing).
You have new config values:
[cluster]
# To guarantee the stabiliy of your Raft cluster, you can
# rate-limit all write operations to the Raft (excluding
# management overhead). This is in request per second. It
# guarantees that the cluster can never be overwhelmed
# because maybe the disks cannot keep up. Usually, when
# this happens, you would see dropped or missing heartbeats
# and errors that the leader is down, even when the cluster
# is healthy.
# The burst can usually be 2-2x the rps.
#
# default: not set
# overwritten by: HQL_RL_CACHE_RPS
rate_limit_cache_rps = 50000
# overwritten by: HQL_RL_CACHE_BURST
rate_limit_cache_burst = 100000
# overwritten by: HQL_RL_DB_RPS
rate_limit_db_rps = 100000
# overwritten by: HQL_RL_DB_BURST
rate_limit_db_burst = 200000When running Postgres, this setting only makes sense for the cache layer of course.
Bugfix
- The Postgres migration
v24__cust_attrs_token_root.sqlwas named with a lowercasevand was therefore silently skipped byrefinery(which only matches an uppercaseV/Uprefix). On Postgres, thescopes.claims_at_rootcolumn was never created and a fresh bootstrap failed. The migration is renamed toV24__cust_attrs_token_root.sql. - After the Issue change with
v0.35.0the URL to the dashboard that's built for a fresh instance was wrong. It contained an additional/and was therefore invalid.
#1578 - When then config expected an
Integervalue that could not be parsed successfully, you might have seen a misleading error message in some cases.
#1586 - PAM user-groups were not deleted when their user was deleted.
#1591 - It was possible that a
prompt=loginwas ignored in certain scnearios.
#1627 - There was a DB deserialization issue for
email_jobswhen running Postgres.
#1630