siyuan-note/siyuan · error
OIDC redirect URL must end with /api/system/oidc/callback
Error message
OIDC redirect URL must end with /api/system/oidc/callback
What it means
The configured redirect URL parsed but failed structural validation: it must have a non-empty scheme, a non-empty host, a path exactly equal to /api/system/oidc/callback, and no userinfo, query string, or fragment. The message highlights the path because that is the most common failure, but any of those defects trigger it.
Source
Thrown at kernel/model/oidc.go:635
func oidcValidationRedirectURL(c *gin.Context, config *conf.OIDC, mobile bool) (string, error) {
if mobile {
return oidcMobileRedirectURL, nil
}
if config.RedirectURL != "" {
return validatePublicOIDCRedirectURL(config.RedirectURL)
}
return effectiveOIDCRedirectURL(c, oidcFlowDesktop)
}
func validatePublicOIDCRedirectURL(redirectURL string) (string, error) {
if redirectURL == "" {
return "", errors.New("A public HTTPS OIDC redirect URL is required for remote access")
}
parsed, err := url.Parse(redirectURL)
if err != nil || parsed.Scheme == "" || parsed.Host == "" || parsed.Path != "/api/system/oidc/callback" ||
parsed.User != nil || parsed.RawQuery != "" || parsed.Fragment != "" {
return "", errors.New("OIDC redirect URL must end with /api/system/oidc/callback")
}
if parsed.Scheme != "https" {
return "", errors.New("Public OIDC redirect URL must use HTTPS")
}
return parsed.String(), nil
}
func getOIDCProvider(ctx context.Context, redirectURL string) (*oidc_provider.Provider, error) {
version := oidcConfigurationVersion(Conf.GetOIDC())
key := version + "\x00" + redirectURL
oidcProviders.Lock()
if oidcProviders.version != version {
oidcProviders.version = version
oidcProviders.items = map[string]*oidc_provider.Provider{}
}
if provider := oidcProviders.items[key]; provider != nil {
oidcProviders.Unlock()
return provider, nilView on GitHub (pinned to 251596fc0d)
Solutions
- Set the URL to exactly https://<host>/api/system/oidc/callback with no trailing slash, query, fragment, or userinfo.
- Run OIDC validation from the admin UI to confirm the value is accepted.
- Mirror the exact same string in the IdP's allowed redirect URIs.
Example fix
// before RedirectURL: "https://notes.example.com/oidc/callback" // after RedirectURL: "https://notes.example.com/api/system/oidc/callback"
Defensive patterns
Strategy: validation
Validate before calling
// Validate redirect-URL structure exactly as the kernel does, before saving config.
func checkRedirectURL(s string) error {
u, err := url.Parse(s)
if err != nil || u.Scheme == "" || u.Host == "" ||
u.Path != "/api/system/oidc/callback" ||
u.User != nil || u.RawQuery != "" || u.Fragment != "" {
return errors.New("redirect URL must be https://<host>/api/system/oidc/callback with no query/fragment")
}
return nil
} Prevention
- Always use the literal path /api/system/oidc/callback with no trailing slash.
- Never append query parameters or fragments to the redirect URL.
- Mirror the exact same string in the IdP allowed-redirect-URI list.
When it happens
Trigger: validatePublicOIDCRedirectURL receives a URL such as https://host/oidc/callback, https://host/api/system/oidc/callback/ (trailing slash), host/api/system/oidc/callback (no scheme), or https://host/api/system/oidc/callback?next=/ (query).
Common situations: Operator copies a redirect URL from another app; trailing slash; path typo; appending query parameters meant for the IdP rather than SiYuan.
Related errors
- A public HTTPS OIDC redirect URL is required for remote acce
- Public OIDC redirect URL must use HTTPS
- full-manual mode requires 'push' or 'pull' subcommand
- Please specify the daily note save path in the Notebook Sett
- 0
AI-assisted analysis of siyuan-note/siyuan@251596fc0d (2026-08-12).
Data as JSON: /api/errors/73cbc975f293b0ee.
Report an issue: GitHub.