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

  1. Check the callback request for error/error_description query params and show the provider's message to the user instead of retrying
  2. Re-initiate login from the beginning (new authorize URL / poll token) so the provider issues a fresh authorization code
  3. Verify the redirect URI and client configuration at the provider so normal logins return a code
  4. 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

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


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)