siyuan-note/siyuan · error

OIDC configuration changed during login

Error message

OIDC configuration changed during login

What it means

Each OIDC transaction records the OIDC configuration version at creation time. claimOIDCTransaction compares it against the current configuration version and, on mismatch, deletes the transaction and fails with this error. This prevents a login started under one IdP configuration from being completed after the settings changed (e.g. swapped client ID or issuer), which would otherwise mix tokens/identities across configurations.

Solutions

  1. Start a new OIDC login after the configuration change — the fresh transaction will carry the new version
  2. Coordinate OIDC setting changes with active users to avoid mid-flight logins
  3. Retry the login once; do not reuse the old authorization URL
Defensive patterns

Strategy: retry

Validate before calling

if tx.ConfigVersion != oidcConfigurationVersion(Conf.GetOIDC()) {
    // transaction is stale; restart the login instead of claiming
}

Try / catch

tx, _, err := claimOIDCTransaction(ctx, state, binding, false)
if err != nil && strings.Contains(err.Error(), "configuration changed") {
    // surface a 'settings changed, please sign in again' message and restart the flow
}

Prevention

When it happens

Trigger: User starts an OIDC login, then someone saves new OIDC settings (issuer, client ID/secret, endpoints); the callback from the old authorization request then arrives and is rejected.

Common situations: Administrator rotates OIDC credentials or switches IdP while users are mid-login; config sync pushed new settings between login start and callback.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


AI-assisted analysis of siyuan-note/siyuan@9f775e8a12 (2026-09-19). Data as JSON: /api/errors/0dd859671bb627b8. Report an issue: GitHub.

Appendix: source

Thrown at kernel/model/oidc.go:694

	return nil
}

func claimOIDCTransaction(ctx context.Context, state, binding string,
	allowDesktopWithoutBinding bool) (*oidcTransaction, bool, error) {
	if state == "" {
		return nil, false, errors.New("OIDC state is missing")
	}
	oidcTransactions.Lock()
	cleanupOIDCTransactionsLocked()
	transaction := oidcTransactions.byState[state]
	if transaction == nil {
		oidcTransactions.Unlock()
		return nil, false, errors.New("OIDC login transaction was not found or has expired")
	}
	if transaction.ConfigVersion != oidcConfigurationVersion(Conf.GetOIDC()) {
		deleteOIDCTransactionLocked(state)
		oidcTransactions.Unlock()
		return nil, false, errors.New("OIDC configuration changed during login")
	}
	if !(allowDesktopWithoutBinding && (transaction.Flow == oidcFlowDesktop || transaction.Flow == oidcFlowValidate)) &&
		(binding == "" || binding != transaction.Binding) {
		oidcTransactions.Unlock()
		return nil, false, errors.New("OIDC login binding does not match")
	}
	if !transaction.Claimed {
		transaction.Claimed = true
		copy := *transaction
		oidcTransactions.Unlock()
		return &copy, false, nil
	}
	done := transaction.Done
	oidcTransactions.Unlock()

	select {
	case <-ctx.Done():
		return nil, false, fmt.Errorf("wait for OIDC login transaction failed: %w", ctx.Err())

View on GitHub (pinned to 9f775e8a12)