Skip to content

External Login Providers

Chatto can consume external OAuth and OIDC providers for sign-in. Providers are configured in chatto.toml as repeated [[auth.providers]] tables, and the login page renders one button per configured provider.

TypeUse for
oidcAny standards-compatible OIDC provider
githubGitHub OAuth apps
gitlabGitLab OAuth applications
googleGoogle OAuth clients
discordDiscord OAuth2 applications

Other provider types are not exposed as curated providers yet. Use oidc for standards-compatible OIDC providers.

Every provider needs a stable id. The ID appears in login URLs and is stored in external identity links, so changing it after users link accounts will strand those links.

Use short, URL-safe IDs that describe the local provider slot:

id = "chatto-hub"
id = "github-main"
id = "staff-google"

Provider IDs must not contain spaces, /, ?, or #.

Register this callback URL with each external provider:

https://chat.example.com/auth/providers/{providerID}/callback

For example, a provider with id = "github-main" on https://chat.example.com uses:

https://chat.example.com/auth/providers/github-main/callback

Chatto derives the callback from webserver.url, so set that value to the public HTTPS origin of your server.

For older OIDC client registrations, Chatto also serves /auth/oidc and /auth/oidc/callback as compatibility aliases for the configured OIDC provider. New registrations should use the provider-specific callback URL.

[webserver]
url = "https://chat.example.com"
[[auth.providers]]
id = "chatto-hub"
type = "oidc"
label = "Chatto Hub"
issuer_url = "https://hub.chatto.dev"
client_id = "..."
client_secret = "..."
# Keep false for invite-only/account-linking deployments.
auto_provision = false

issuer_url must be an absolute http or https URL. Chatto uses OIDC discovery from that issuer and verifies the ID token before matching the external identity.

By default, Chatto does not request email claims from OIDC providers:

[[auth.providers]]
id = "idp-main"
type = "oidc"
label = "Company SSO"
issuer_url = "https://idp.example.com"
client_id = "..."
client_secret = "..."
auto_provision = true

Email-less accounts can sign in, link identities, and count toward limits.max_users through the linked OIDC subject. They do not receive a Chatto verified email unless the provider later returns an explicitly verified email claim.

By default, Chatto requests the minimum provider scopes needed to identify the provider account. Email scopes are only requested when request_email = true.

TypeScopes when request_email = falseScopes when request_email = true
oidcopenid, profileopenid, profile, email
githubnoneread:user, user:email
gitlabnoneread_user
googleopenid, profileopenid, profile, email
discordidentifyidentify, email

You can override scopes per provider:

[[auth.providers]]
id = "chatto-hub"
type = "oidc"
issuer_url = "https://id.example.com"
client_id = "..."
client_secret = "..."
scopes = ["openid", "profile", "groups"]

For OIDC providers, Chatto always includes openid even if you omit it from a custom scope list.

request_email defaults to false. Set request_email = true to request provider email scopes. For OIDC, the default request is openid profile; Chatto can create, link, and sign in accounts from the provider sub without receiving an email claim.

auto_provision controls whether an unlinked provider identity may create a new account.

  • auto_provision = false is the safe default. Unlinked users are returned to the login screen with an explanation, and existing users can still link the provider from account settings.
  • auto_provision = true creates a short-lived pending account-creation flow after the provider callback. The user must explicitly confirm the username before the account is created.

Auto-provisioning never silently merges by email. If a person already has a local account, they should sign in with that account and link the provider from account settings.

Chatto matches external logins by provider identity, not by email address.

  • OIDC providers are matched by verified issuer URL plus subject.
  • OAuth-only providers are matched by the configured provider ID plus provider user ID.
  • Email claims are optional profile data and are not used to pick an account.

If a provider callback returns an identity that is not linked to an account, Chatto does not silently pick an account by email.

Set auto_provision = true on a provider to allow new users from that provider to create accounts. If auto_provision is omitted or false, an unlinked provider identity cannot create an account.

Existing users can link providers from their account settings. Linking requires the user to already be signed in, lets Chatto create a short-lived provider link-start URL, and asks the user to confirm the pending link after the provider callback. Pending create and link tokens are short-lived and scoped to that specific action.

Accounts created through an email-less provider are passwordless until the user adds a password in account settings. Password reset by email requires a verified email address, so operators running SSO without email should keep at least one trusted provider link available for affected users.

A linked external identity is a verified sign-in factor. It is enough for login and for limits.max_users, even when the provider did not return an email address.

A Chatto verified email is stricter. Chatto creates one from a provider email only when the provider adapter has an explicit verification signal:

ProviderWhen Chatto stores a verified email
oidcemail is present and email_verified = true
githubThe GitHub emails API returns a verified primary email
googleGoth profile data includes verified_email or email_verified
discordGoth profile data includes verified = true
gitlabNot currently promoted to a Chatto verified email

Verified email matters for email password reset and for owners.emails owner promotion. A linked SSO identity alone does not match owners.emails.

Public clients can discover configured providers through server discovery:

  • chatto.discovery.v1.ServerDiscoveryService.GetServer returns provider IDs, types, labels, and login URLs in login.providers.

You can call the discovery RPC with Connect JSON:

Terminal window
curl -X POST https://chat.example.com/api/connect/chatto.discovery.v1.ServerDiscoveryService/GetServer \
-H 'Content-Type: application/json' \
-H 'Connect-Protocol-Version: 1' \
--data '{}'

Provider IDs stay provider-specific, so an OIDC provider can use an ID such as chatto-hub while reporting its provider type as oidc.