siyuan-note/siyuan · error

OIDC issuer URL is required

Error message

OIDC issuer URL is required

What it means

Thrown by oidc_provider.New() when issuerURL is empty after the provider switch resolves. Google hard-codes its issuer, GitHub returns early before this check, but Microsoft and Custom rely on config.IssuerURL being populated. If the admin selected Custom or Microsoft but left the issuer URL blank, discovery cannot proceed.

Source

Thrown at kernel/model/oidc_provider/provider.go:61

		return nil, errors.New("OIDC redirect URL is required")
	}
	if config.Provider == conf.OIDCProviderGitHub && config.ClientSecret == "" {
		return nil, errors.New("GitHub OAuth client secret is required")
	}
	issuerURL := strings.TrimSpace(config.IssuerURL)
	switch config.Provider {
	case conf.OIDCProviderGoogle:
		issuerURL = googleIssuer
	case conf.OIDCProviderMicrosoft:
		// Microsoft 多租户端点的 issuer 会随租户变化,必须使用租户专属 issuer。
	case conf.OIDCProviderCustom:
	case conf.OIDCProviderGitHub:
		return newGitHub(config, redirectURL), nil
	default:
		return nil, fmt.Errorf("unsupported OIDC provider [%s]", config.Provider)
	}
	if issuerURL == "" {
		return nil, errors.New("OIDC issuer URL is required")
	}
	discovered, err := oidc.NewProvider(ctx, issuerURL)
	if err != nil {
		return nil, fmt.Errorf("discover OIDC provider failed: %w", err)
	}
	scopes := append([]string{}, config.Scopes...)
	if !contains(scopes, oidc.ScopeOpenID) {
		scopes = append([]string{oidc.ScopeOpenID}, scopes...)
	}
	return &Provider{
		kind: conf.OIDCProviderCustom,
		oauth2Config: &oauth2.Config{
			ClientID:     config.ClientID,
			ClientSecret: config.ClientSecret,
			Endpoint:     discovered.Endpoint(),
			RedirectURL:  redirectURL,
			Scopes:       scopes,
		},

View on GitHub (pinned to 251596fc0d)

Solutions

  1. For Custom provider: enter the full issuer URL from your OIDC provider's well-known configuration (e.g., https://provider.example.com/.well-known/openid-configuration — use the base, not the .well-known path).
  2. For Microsoft: provide the tenant-specific issuer URL since the multi-tenant endpoint issuer varies.
  3. Validate IssuerURL is non-empty in the API handler when provider is Custom or Microsoft.

Example fix

// before
config.Provider = conf.OIDCProviderCustom
config.IssuerURL = ""

// after
config.Provider = conf.OIDCProviderCustom
config.IssuerURL = "https://keycloak.example.com/realms/myrealm"
Defensive patterns

Strategy: validation

Validate before calling

if (config.Provider == conf.OIDCProviderCustom || config.Provider == conf.OIDCProviderMicrosoft) && strings.TrimSpace(config.IssuerURL) == "" {
    return nil, errors.New("OIDC issuer URL is required for custom and Microsoft providers")
}
provider, err := oidc_provider.New(ctx, config, redirectURL)

Type guard

func hasIssuerURL(c *conf.OIDC) bool {
    switch c.Provider {
    case conf.OIDCProviderGoogle, conf.OIDCProviderGitHub:
        return true // issuer is hardcoded or not needed
    }
    return strings.TrimSpace(c.IssuerURL) != ""
}

Prevention

When it happens

Trigger: Calling New() with config.Provider == conf.OIDCProviderCustom or conf.OIDCProviderMicrosoft, and config.IssuerURL is empty or whitespace-only (TrimSpace yields empty). The switch falls through without setting issuerURL, and the subsequent empty check fires.

Common situations: The admin chose 'Custom' OIDC provider to connect a self-hosted Keycloak/Authelia/etc. but did not fill in the issuer URL (e.g., https://keycloak.example.com/realms/myrealm). The Microsoft provider was selected but the tenant-specific issuer URL was not provided.

Related errors


AI-assisted analysis of siyuan-note/siyuan@251596fc0d (2026-08-12). Data as JSON: /api/errors/fcdecd61c814ef8a. Report an issue: GitHub.