siyuan-note/siyuan · error

OIDC state is missing

Error message

OIDC state is missing

What it means

claimOIDCTransaction received an empty state string. The state correlates the IdP callback to the stored transaction; without it nothing can be looked up and the request is rejected immediately before any locking.

Source

Thrown at kernel/model/oidc.go:738

		}
		if transaction.Binding != "" && candidate.Binding == transaction.Binding {
			perBinding++
		}
	}
	if perIP >= oidcTransactionPerIP || perBinding >= oidcTransactionPerBind {
		return errors.New("too many pending OIDC login transactions")
	}
	oidcTransactions.byState[transaction.State] = transaction
	if transaction.PollToken != "" {
		oidcTransactions.byPoll[transaction.PollToken] = transaction.State
	}
	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")
	}

View on GitHub (pinned to 251596fc0d)

Solutions

  1. Restart the OIDC flow via /api/system/oidc/start to obtain a fresh state.
  2. Verify the IdP redirect configuration preserves the state parameter end to end.
  3. Check the client passes the state through unchanged from start to callback.
Defensive patterns

Strategy: validation

Validate before calling

// Reject callbacks/polls with no state before reaching the kernel's claim path.
if c.Query("state") == "" {
    return errors.New("missing state parameter")
}

Prevention

When it happens

Trigger: A request reaches /api/system/oidc/callback or the desktop/validate poll without a state query/body parameter; the IdP dropped state from its redirect; a manual/curled callback omitted it.

Common situations: IdP mis-configured to strip state; client bug losing the parameter between start and callback; direct browser hit on the callback URL.

Related errors


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