Skip to content

Update email settings

PUT
/api/v1/admin/settings/email
Code sample: Shell / cURL
curl --request PUT \
--url http://localhost:9090/api/v1/admin/settings/email \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '{ "smtpEnabled": true, "smtpHost": "example", "smtpPort": 1, "smtpUsername": "example", "smtpPassword": "example", "clearSmtpPassword": false, "smtpEncryption": "example", "smtpFromName": "example", "smtpFromEmail": "example" }'

Update SMTP/email settings. A change needs authserver:manage: these settings decide where password reset links are sent, so authserver:manage-settings reads them but is refused a change with 403 MANAGE_SCOPE_REQUIRED. A save with smtpEnabled: false clears every SMTP field, the stored password included.

The stored SMTP password is kept, replaced or removed: an absent or empty smtpPassword keeps it, a non-empty one replaces it, and clearSmtpPassword: true removes it. The two together are refused with 400 VALIDATION_ERROR.

A stored password reaches only the host it was entered for: a save that changes smtpHost while a password is stored, carrying neither a new smtpPassword nor clearSmtpPassword: true, is refused with 400 VALIDATION_ERROR and writes nothing. The hosts are compared with surrounding space trimmed, one pair of brackets taken off an IPv6 literal, and without regard to case. A change of port, username, encryption or sender keeps the stored password.

Once every other check has passed, a save with smtpEnabled: true opens a TCP connection to smtpHost on smtpPort, with a 3-second timeout. It only checks that something answers there: it does not speak SMTP, negotiate TLS or authenticate, which is what the send-test operation is for. A connection that fails is a 400; see that response.

Media typeapplication/json
object
smtpEnabled
boolean
smtpHost
string
smtpPort
integer
smtpUsername
string
smtpPassword

A new SMTP password, at most 256 bytes. The stored password is never returned, only hasSmtpPassword, so an absent or empty value keeps the stored password; a non-empty value replaces it. Sending one together with clearSmtpPassword: true is refused with 400 VALIDATION_ERROR and nothing is written.

string
clearSmtpPassword

true removes the stored SMTP password. Removing it when none is stored is an ordinary save. Refused with 400 VALIDATION_ERROR together with a non-empty smtpPassword. Ignored when smtpEnabled is false, which clears every SMTP field, the password included.

boolean
smtpEncryption
string
smtpFromName
string
smtpFromEmail
string

Settings updated

Media typeapplication/json
object
smtpEnabled
required
boolean
smtpHost
required
string
smtpPort
required
integer
smtpUsername
required
string
smtpEncryption
required
string
smtpFromName
required
string
smtpFromEmail
required
string
hasSmtpPassword
required
boolean

Example generated

{
"smtpEnabled": true,
"smtpHost": "example",
"smtpPort": 1,
"smtpUsername": "example",
"smtpEncryption": "example",
"smtpFromName": "example",
"smtpFromEmail": "example",
"hasSmtpPassword": true
}

Error_code is INVALID_REQUEST_BODY for a body that will not parse; a refused field answers VALIDATION_ERROR, or its catalog key, such as validator.email.invalid_format, when the refusal is localized; and a connection that fails answers VALIDATION_ERROR. Nothing is written.

A failed connection answers one of these fixed messages, naming at most its coarse cause:

  • “Unable to connect to the SMTP server: host name not found.” Check the host name: it is misspelt, or the auth server cannot resolve it, or its resolver did not answer in time. The auth server’s resolver may not be the one your own machine uses.
  • “Unable to connect to the SMTP server: connection timed out.” Nothing answered within 3 seconds: check the port, and any firewall between the auth server and the SMTP server.
  • “Unable to connect to the SMTP server: connection refused.” The host answered but nothing listens on that port: check the port.
  • “Unable to connect to the SMTP server.” Any other failure, such as a network the auth server has no route to.

No address, port or operating-system error is answered; the full error goes to the auth server’s log, at Warn, as “unable to connect to the smtp server” under the request’s request_id.

Media typeapplication/json

Admin/account API error envelope. Routing by HTTP status code: 4xx is a client-correctable failure (validation, not found, permission denied, rate limited); 5xx is a server-side problem. The body provides a stable error_code and an error_description for people to read. Protocol endpoints (/auth/token, /auth/authorize, /connect/register, /userinfo) use their RFC-defined error envelopes instead of this one.

object
error_code

Stable identifier for the failure. UPPER_SNAKE for legacy codes (e.g. VALIDATION_ERROR), dotted lowercase for catalog-keyed localized codes (e.g. validator.email.required).

string
error_description
required

A sentence for people to read: in the request’s language when error_code is a catalog key, in English otherwise. Route on error_code, not on this text.

string

Example generated

{
"error_code": "example",
"error_description": "example"
}

Missing or invalid bearer token

Media typeapplication/json

Admin/account API error envelope. Routing by HTTP status code: 4xx is a client-correctable failure (validation, not found, permission denied, rate limited); 5xx is a server-side problem. The body provides a stable error_code and an error_description for people to read. Protocol endpoints (/auth/token, /auth/authorize, /connect/register, /userinfo) use their RFC-defined error envelopes instead of this one.

object
error_code

Stable identifier for the failure. UPPER_SNAKE for legacy codes (e.g. VALIDATION_ERROR), dotted lowercase for catalog-keyed localized codes (e.g. validator.email.required).

string
error_description
required

A sentence for people to read: in the request’s language when error_code is a catalog key, in English otherwise. Route on error_code, not on this text.

string

Example generated

{
"error_code": "example",
"error_description": "example"
}
WWW-Authenticate
string

Bearer challenge on token refusals. An operation may also return a handler-level 401 without this header.

The token is valid but does not authorise this request. Four checks answer here, and a caller distinguishes them by error_code.

INSUFFICIENT_SCOPE comes from the route’s authorisation middleware, before the handler runs: an Admin operation needs one of the scopes its route names, and an Account operation needs authserver:manage-account.

USER_CONTEXT_REQUIRED comes from the same middleware on the Account operations, which also require the token to have been issued for a user: one obtained through the client credentials grant carries no auth_time claim and is refused here.

FORBIDDEN comes from the handler, on the account endpoints that resolve a resource by id and then check it belongs to the caller, so a valid token for the wrong user reaches this rather than a 404.

MANAGE_SCOPE_REQUIRED comes from the handler, on the Admin operations the administrative policy guards. Only authserver:manage creates an administrator, changes one, or changes what reaches one, so no granular scope will ever be enough: the remedy is a token holding authserver:manage, not requesting the route’s scope as for INSUFFICIENT_SCOPE. An administrator is a user, group or client holding any of the six administrative permissions (manage, admin-read, manage-users, manage-clients, manage-settings, browser-sessions), a user directly or through any of its groups, the admin console’s own client whatever it holds, and a client allowed to request the administrative scopes. A granular scope is refused here when it:

  • grants or revokes an administrative permission, directly or by moving a user into or out of a group that holds one, or deletes such a group;
  • writes to an administrator user (profile, credentials, enabled, sessions, consents, attributes, memberships, permissions, deletion), an administrative group (settings, attributes, members, permissions, deletion), or an administrator client (settings, authentication, flows, redirect URIs, web origins, token settings, permissions, logo, deletion);
  • switches whether a client may request the administrative scopes, on or off, on any client;
  • reads an administrator client’s secret;
  • changes the email or the audit-log settings;
  • changes an administrative permission’s description. Granular scopes still read administrators. The refusal is answered after the request’s 400 and 404, writes nothing, carries WWW-Authenticate: Bearer realm="goiabada", error="insufficient_scope", error_description="...", scope="authserver:manage", and leaves an administrator_change_refused audit record.

Every operation this document secures declares a 403. The public client logo endpoint, which carries security: [] and authorises nothing, is the one that does not.

Media typeapplication/json

Admin/account API error envelope. Routing by HTTP status code: 4xx is a client-correctable failure (validation, not found, permission denied, rate limited); 5xx is a server-side problem. The body provides a stable error_code and an error_description for people to read. Protocol endpoints (/auth/token, /auth/authorize, /connect/register, /userinfo) use their RFC-defined error envelopes instead of this one.

object
error_code

Stable identifier for the failure. UPPER_SNAKE for legacy codes (e.g. VALIDATION_ERROR), dotted lowercase for catalog-keyed localized codes (e.g. validator.email.required).

string
error_description
required

A sentence for people to read: in the request’s language when error_code is a catalog key, in English otherwise. Route on error_code, not on this text.

string

Example generated

{
"error_code": "example",
"error_description": "example"
}
WWW-Authenticate
string

Bearer challenge on scope and administrative-policy refusals; other forbidden responses omit it.

The request failed inside the server, most often a storage error. error_code is INTERNAL_SERVER_ERROR: no detail about the failure, only the request id an operator can find the log line by, and retrying is reasonable. Key rotation’s 500 also answers KEY_SET_INCOMPLETE, which names its cause and no retry clears.

Media typeapplication/json

Admin/account API error envelope. Routing by HTTP status code: 4xx is a client-correctable failure (validation, not found, permission denied, rate limited); 5xx is a server-side problem. The body provides a stable error_code and an error_description for people to read. Protocol endpoints (/auth/token, /auth/authorize, /connect/register, /userinfo) use their RFC-defined error envelopes instead of this one.

object
error_code

Stable identifier for the failure. UPPER_SNAKE for legacy codes (e.g. VALIDATION_ERROR), dotted lowercase for catalog-keyed localized codes (e.g. validator.email.required).

string
error_description
required

A sentence for people to read: in the request’s language when error_code is a catalog key, in English otherwise. Route on error_code, not on this text.

string

Example generated

{
"error_code": "example",
"error_description": "example"
}