siyuan-note/siyuan · error
OIDC authorization code is missing
Error message
OIDC authorization code is missing
What it means
finishOIDCExchange completes the OAuth2/OIDC authorization-code exchange. The OAuth2 authorization-code grant requires the code query parameter returned by the provider; if code is empty the exchange cannot proceed, so the handler rejects it immediately. Providers send an error parameter instead of code on failures, which can surface as an empty code.
Solutions
- Check the callback request for error/error_description query params and show the provider's message to the user instead of retrying
- Re-initiate login from the beginning (new authorize URL / poll token) so the provider issues a fresh authorization code
- Verify the redirect URI and client configuration at the provider so normal logins return a code
- Do not reuse or replay old callback URLs — codes are single-use and short-lived
Example fix
// before
// callback URL: /api/oidc/callback (no code param) -> error
// after
// handle provider error redirect first
if c.Query("error") != "" { renderAuthError(c, c.Query("error_description")); return }
err := model.OIDCCallback(c, c.Query("code")) Defensive patterns
Strategy: validation
Validate before calling
// before invoking the callback handler, ensure the code param exists
if c.Query("code") == "" && c.Query("error") != "" { renderProviderError(c, c.Query("error_description")); return } Try / catch
if err := model.OIDCCallback(c, code); err != nil && strings.Contains(err.Error(), "authorization code is missing") {
renderAuthError(c, "Login was cancelled or the provider returned no code; please retry")
} Prevention
- Handle the provider's error= redirect explicitly instead of letting it hit the code path
- Never bookmark or replay callback URLs
- Verify redirect URI configuration at the IdP so error redirects are distinguishable
When it happens
Trigger: OIDCCallback or OIDCMobileCallback invoked without ?code= — e.g. the provider redirected back with an error= parameter (user denied consent), the callback URL was opened directly/manually, or the frontend invoked the mobile callback without forwarding the code.
Common situations: User cancels at the provider's consent screen and the provider redirects back without a code; misconfigured redirect URI causing a provider error redirect; a browser bookmark of the callback URL; network-truncated redirect dropping query params.
Related errors
- exchange OIDC authorization code failed
- GitHub OAuth client secret is required
- OAuth callback did not include an authorization code
- OIDC redirect URL is required
- OIDC response does not contain an ID token
AI-assisted analysis of siyuan-note/siyuan@9f775e8a12 (2026-09-19).
Data as JSON: /api/errors/4d1671d82043b58d.
Report an issue: GitHub.
Appendix: source
Thrown at kernel/model/oidc.go:843
}
if err := authenticateOIDCSession(c, transaction.RememberMe); err != nil {
return writeOIDCCallbackPage(c, false, oidcUserMessage())
}
return apicontract.RedirectHTTPContent(http.StatusFound, safeOIDCRedirectTarget(transaction.To))
}
func cleanupOIDCTransactionsLocked() {
now := time.Now()
for state, transaction := range oidcTransactions.byState {
if now.After(transaction.ExpiresAt) {
deleteOIDCTransactionLocked(state)
}
}
}
func finishOIDCExchange(c *gin.Context, transaction *oidcTransaction, code string) error {
if code == "" {
return errors.New("OIDC authorization code is missing")
}
config := Conf.GetOIDC()
provider := transaction.Provider
if transaction.Flow == oidcFlowValidate {
if transaction.Config == nil || provider == nil {
return errors.New("OIDC validation configuration is missing")
}
config = transaction.Config
} else {
var err error
provider, err = getOIDCProvider(c.Request.Context(), transaction.RedirectURL)
if err != nil {
return err
}
}
exchangeContext, cancel := context.WithTimeout(c.Request.Context(), oidcExchangeTimeout)
defer cancel()
claims, err := provider.Exchange(exchangeContext, code, transaction.CodeVerifier, transaction.Nonce)View on GitHub (pinned to 9f775e8a12)