Skip to content

Email and OAuth2

Email login and OAuth2 providers use runtime settings. Email uses the email group, and OAuth2 providers use oauth2.providers.

Email settings are stored in PostgreSQL and hot-reloaded across cluster nodes:

终端窗口
synctv settings update \
--set email.smtpHost=smtp.example.com \
--set email.smtpPort=465 \
--set 'email.smtpCredentials={"username":"[email protected]","password":"secret"}' \
--set 'email.smtpProxy={"url":"socks5://proxy.example.com:1080"}' \
--set email.useTls=true \
--set email.fromName=SyncTV \
--set email.enabled=true
Field Default Meaning
email.enabled false Enable email delivery
email.smtpHost null SMTP server host
email.smtpPort 587 SMTP port
email.smtpCredentials null Optional SMTP credentials {username, password}
email.smtpProxy null Optional SOCKS5 proxy {url, credentials?}
email.fromEmail null Sender email address; required and validated when email is enabled
email.fromName SyncTV Sender display name
email.useTls true Whether SMTP uses TLS

updateMask identifies the fields to replace. To clear smtpHost, fromEmail, smtpCredentials, or smtpProxy, keep its path in updateMask and omit the field from settings.email. Management reads return usernames and the proxy URL while omitting passwords. Omitting password preserves it when the username is unchanged; new credentials and username changes require a password. The proxy resolves the SMTP target hostname. Email verification codes, password reset, and email MFA depend on these SMTP settings. Standalone email login only serves existing accounts; the code request API intentionally returns a generic message to avoid account enumeration. Email signup and review policy live in Runtime Settings.

oauth2.providers is an array of OAuth2ProviderSettings objects. Each element has an instanceName such as github, logto1, or corp_oidc. Instance names may contain only ASCII letters, digits, _, and -.

Every instance uses shared fields plus one provider oneof field:

{
"instanceName": "github",
"enableSignup": true,
"signupNeedReview": false,
"github": {
"clientId": "github-client-id",
"clientSecret": "github-client-secret"
}
}

Fields:

Field Meaning
instanceName Provider instance name
enableSignup Whether first-time login through this provider can create a local account
signupNeedReview Whether first-time signup should enter the review queue
provider oneof field qq, github, google, microsoft, discord, casdoor, logto, oidc, feishu, gitee, or apple; provider-private fields live inside that object
[
{
"instanceName": "github",
"enableSignup": true,
"signupNeedReview": false,
"github": {
"clientId": "github-client-id",
"clientSecret": "github-client-secret"
}
}
]
  • When runtime settings change, the OAuth2 service rebuilds its provider map from the new value.
  • Missing instance names mean the login entry point is unavailable.
  • enableSignup=false only blocks first-time account creation through that provider. Existing linked OAuth2 logins still work.
  • signupNeedReview=true sends first-time OAuth2 signup into the review flow.

Browser authorization requests pass redirectUrl; the server validates HTTPS callbacks against oauth2.allowedRedirectUrls, while loopback callbacks are handled separately. Register the same callback URL with the third-party provider.

Native authorization requests omit redirectUrl and pass native=true. The Apple provider advertises native support through supportedModes; iOS and Mac App Store builds use Apple’s system Sign in with Apple flow and return an authorization code to the client, which exchanges it with the SyncTV server. macOS Developer ID builds use browser authorization. The server rejects modes that the provider has not advertised.

Native Apple login does not use /.well-known/apple-app-site-association. That document is used for Apple Universal Links, browser OAuth callback association, and passkey association.

Put provider secrets in the provider configuration and manage them through runtime settings. Apple uses separate webClientSecret and nativeClientSecret values.