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 public OIDC redirect URL must parse to an absolute http(s) URL whose path is exactly /api/system/oidc/callback, with no userinfo, query, or fragment; anything else cannot be matched against the fixed callback endpoint, so validatePublicOIDCRedirectURL rejects it.
Solutions
- Use the exact path /api/system/oidc/callback: https://<host>/api/system/oidc/callback
- Remove any query string, fragment, or userinfo from the URL
- Ensure the URL includes scheme and host (https://your-domain/...), not just a path
Example fix
// before RedirectURL: "https://siyuan.example.com/oidc?brand=siyuan" // after RedirectURL: "https://siyuan.example.com/api/system/oidc/callback"
Defensive patterns
Strategy: validation
Validate before calling
function validPublicRedirect(u) {
try {
const p = new URL(u);
return p.protocol === 'https:' && p.pathname === '/api/system/oidc/callback' && !p.search && !p.hash && !p.username && !p.password;
} catch { return false; }
} Try / catch
if err := validatePublicOIDCRedirectURL(cfg.RedirectURL); err != nil {
// correct to https://<host>/api/system/oidc/callback and retry
} Prevention
- Always append /api/system/oidc/callback to your public base URL
- No query strings, fragments, or credentials in the redirect URL
- Validate the URL client-side with URL parsing before saving
When it happens
Trigger: url.Parse fails, or parsed.Scheme/Host empty, parsed.Path != "/api/system/oidc/callback", or parsed.User/RawQuery/Fragment non-empty — for any configured RedirectURL passed via ValidateOIDCProviderConfiguration, ValidateOIDCConfigurationChange, oidcValidationRedirectURL, or effectiveOIDCRedirectURL.
Common situations: Entering only the domain or a trailing-slash path (e.g. https://x.com/oidc) instead of the full callback path; appending ?tenant=... parameters; forgetting https:// so Host parses as Path; copying a provider's own redirect format.
Understand the failure class
Background: "Invalid URL" errors: why new URL(), URI.parse, and reqwest::Url reject your string — missing scheme, whitespace, and bad path format — this error's family across 39 libraries.
Related errors
- A loopback OIDC redirect URL is required for local access
- A public HTTPS OIDC redirect URL is required for remote…
- CalDAV: calendar object path is invalid
- CalDAV: calendar path is invalid
- CardDAV: address book path is invalid
AI-assisted analysis of siyuan-note/siyuan@9f775e8a12 (2026-09-19).
Data as JSON: /api/errors/73cbc975f293b0ee.
Report an issue: GitHub.
Appendix: source
Thrown at kernel/model/oidc.go:579
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 9f775e8a12)