Skip to content

Core concepts ​

This page ties together the terms that keep coming up in Wicket: who issues tokens, to whom, what is issued, on what basis, and who wires all of this together in code.

Issuer ​

The issuer is the authorization server's identifier. It is written into the iss claim of every token and is the issuer field of the discovery document.

  • If WicketOptions.IssuerUri is set, the issuer is that value (with any trailing / removed).
  • If it is not set, Wicket derives the issuer from the current request: http(s):// + r.Host, where https is chosen solely by whether r.TLS is non-nil.

Always set IssuerUri explicitly in production. Otherwise the same service reached through different host names yields different issuers, and token validation fails as a result.

go
opts := godi.GetRequired[*options.WicketOptions](root)
opts.IssuerUri = "https://id.example.com"

Clients ​

A client is an application that requests tokens from Wicket: a backend service, a single-page app, a mobile app, a device, and so on. Clients are described by storage/models.Client. Key fields:

  • ClientId / ClientSecrets: the client identifier and secrets (secrets are stored hashed with utils.Sha256).
  • Allowed grant types: set through SetAllowedGrantTypes (the field itself is unexported, and invalid combinations are rejected).
  • AllowedScopes: the scopes the client may request.
  • RedirectUris: the allowlist of redirect URIs for the authorization code flow.

See Clients and resources for details.

Resources and scopes ​

Wicket splits "what a token can access" into three models:

ModelPurposeAppears in
IdentityResource (identity resource)A group of user identity claims, such as openid→sub, profile→name, and so onID token, UserInfo
ApiScope (API scope)A single access permission a client can request, such as orders.readThe access token's scope
ApiResource (API resource)A protected API that groups several ApiScopes and holds the ApiSecrets used for introspectionThe access token's aud; the caller identity at the introspection endpoint

When a client requests scope=openid profile orders.read, openid and profile match identity resources, orders.read matches an API scope, and the name of the API resource it belongs to goes into the access token's audience.

Tokens ​

TokenPurposeFormat
Access tokenCalling APIsJWT (header typ is at+jwt), signed with RS256 by default
Reference tokenAn alternative format for access tokensAn opaque handle; the token contents live in ReferenceTokenStore, and APIs must call the introspection endpoint to validate it. Not issued yet in v0.1.4; see the note below
ID tokenProves to the client "who logged in"JWT, issued only for OIDC requests (those that include the openid scope)
Refresh tokenExchanged for new access tokensAn opaque handle stored in RefreshTokenStore; the client needs AllowOfflineAccess = true and must request offline_access

Reference tokens are not wired up in v0.1.4

The Client.AccessTokenType field can be set to wicket.AccessTokenTypeReference, but the v0.1.4 issuance path does not read it: in testing, the token endpoint still returns a JWT after setting it. ReferenceTokenStore is currently used only on the token validation side. If you need access tokens that can be revoked immediately, shorten AccessTokenLifetime.

Grant types ​

Grant typeConstantTypical scenario
client_credentialswicket.GrantTypesClientCredentialsService to service, no user involved
authorization_codewicket.GrantTypesCodeWeb / mobile / SPA with a user login; PKCE required by default
refresh_token—Renewal with a refresh token. It does not need to be listed in the client's allowed grant types; refresh tokens are issued only when the client has AllowOfflineAccess = true and the request includes offline_access
CIBA (urn:openid:params:grant-type:ciba)wicket.GrantTypesBackchannelAuthenticationInitiated over the backchannel; the user confirms on another device
Device code (urn:ietf:params:oauth:grant-type:device_code)wicket.GrantTypesDeviceFlowThe token endpoint can handle it, but v0.1.4 has no built-in device authorization endpoint
passwordwicket.GrantTypesPasswordRejected by default; the host must inject a validator with cfg.SetResourceOwnerValidator

For the full steps of each flow, see Flows.

Authentication schemes ​

An "authentication scheme" is how the host application recognizes the user who is logged in on the browser side. Wicket predefines two cookie-based scheme names:

Scheme nameConstantPurpose
wicketwicket.DefaultCookieAuthenticationSchemeThe main session cookie after the user logs in on the host's login page
wicket.externalwicket.ExternalCookieAuthenticationSchemeTemporarily holds the external identity during an external login (Google, Facebook, etc.) callback

v0.1.4 has no built-in cookie handler

By default both schemes are registered with an "unsupported" placeholder handler: authentication always yields "not logged in", and Challenge returns an error. To run flows that require a user login (authorization code, end session, etc.), the host must provide its own auth.Handler implementation for these two schemes:

go
cfg.SetAuthenticationHandlerProvider(wicket.DefaultCookieAuthenticationScheme,
	func(p godi.Provider) auth.Handler { return newMyCookieHandler(p) }) // newMyCookieHandler is implemented by the host (illustrative)

Flows that involve no browser user, such as client_credentials, are not affected.

Handlers for the Google, Facebook, and Bearer (JWT Bearer) schemes are also built in; see Identity.

Composition root (di.Root) and ServerConfig ​

All of Wicket's services are wired by a code-generated dependency injection container. The entry point is di.NewRoot():

go
root, err := di.NewRoot()   // returns (*di.Root, error)
if err != nil { log.Fatal(err) }
defer root.Close()

opts := godi.GetRequired[*options.WicketOptions](root) // protocol options
cfg  := root.ServerConfig()                            // host injection point

The two objects have clearly separated roles:

  • *options.WicketOptions: switches and parameters for protocol behavior (issuer, endpoints, interaction page URLs, input length limits, and so on). See Configuration.
  • *di.ServerConfig: where the host injects "the outside world" into Wicket: client and resource lists, signing credentials, the various stores, authentication handlers, the profile service, and so on. Every injection method takes one of two forms: SetXxx(value) or SetXxxProvider(func() value).

Once wiring is complete, call cfg.Freeze(). It checks that every storage port has been injected (or that an in-memory fallback has been declared), and panics immediately otherwise. After that, build the server with server.DefaultServer(root, ...) and get the middleware with srv.UseWicket(). See Embedding in a host application for details.

The three storage port families ​

Wicket accesses its stateful data through three families of interfaces (ports), and the host injects the implementations:

Port familyPackageWhat it storesInjection methods
storagestorageAuthorization codes, refresh tokens, reference tokens, user consents, persisted grants, device codes, CIBA requests, authorization parameter messagesSetAuthorizationCodeStore, SetRefreshTokenStore, etc.
sessionsessionServer-side session recordsSetSessionStore
keymgmtkeymgmtAutomatically managed signing keys and their lifecycleSetRecordStore

There are also two kinds of input that are not "persistence": clients and resources (SetClients, etc., which are configuration data), and signing credentials and validation keys (SetSigningCredentialStores / SetValidationKeysStores).

Each family has a matching conformance suite (storage/storagetest, session/sessiontest, keymgmt/keymgmttest), and an adapter is only considered compliant once it passes its suite. See Persistence and Storage ports for details.

Released under the Apache License 2.0 · Documentation © 2026 Wicket authors