Production checklist
Go through these items one by one before going live. Each item corresponds to a mechanism or known limitation that actually exists in Wicket v0.1.4; Wicket won't handle items marked "host responsibility" for you.
Network and issuer
Serve only HTTPS externally. Wicket doesn't terminate TLS; the host process (
ListenAndServeTLS) or a front proxy does. OIDC browser endpoints require TLS, andServerSideSessions.CookieSecurefor the server-side session cookie already defaults totrue.Set
IssuerUriexplicitly, exactly matching the authority configured on clients and resources (includinghttps://, with no trailing/). When it isn't set, the issuer changes with the request'sHost, and token validation fails across different entry points.Handle reverse-proxy headers (host responsibility). Wicket doesn't read
X-Forwarded-*/Forwarded.IssuerUrionly pinsiss; the endpoint URLs in the discovery document are still derived fromr.Hostandr.TLS, so when TLS is terminated at the proxy they becomehttp://<internal address>. You can add a middleware outside Wicket that trusts only your own proxy (tested on v0.1.4; the discovery document then outputshttps://id.example.com/...):gofunc trustProxy(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { // Only do this when the request really comes from your proxy (for example, check the source network) if r.Header.Get("X-Forwarded-Proto") == "https" { r.TLS = &tls.ConnectionState{} } if h := r.Header.Get("X-Forwarded-Host"); h != "" { r.Host = h } next.ServeHTTP(w, r) }) } handler := trustProxy(hosting.ScopeMiddleware(root)(srv.UseWicket()(app)))Mount at the site root. Wicket's URL computation doesn't support a subpath prefix; see Embedding in a host application.
Storage
- Don't call
cfg.AllowInMemoryFallback(). It is for development only. - Inject all 11 store seams and call
cfg.Freeze(), so that anything missing surfaces as a panic at startup instead of silently falling back to memory. wicket-pg provides 9 of them; the other two (the authorization parameters message store and the distributed cache) must be handled explicitly by the host; see Persistence. - Run
migrations.Upin the startup sequence, and consider usingConformsTo()to check that the adapter matches Wicket's contract version. - The host closes the connection pool;
root.Close()doesn't.
Signing keys
- Keys are consistent across restarts and replicas. Manual approach: all replicas load the same private key (with the RFC 7638 thumbprint as kid, the kids naturally agree). Automatic approach: all replicas share the same persistent
keymgmt.RecordStore(such as wicket-pg'sNewKeyRecordStore). - When enabling automatic rotation, wire it the v0.1.4 way: build your own
keymgmt.Managerand inject adapters; changingopts.KeyManagementhas no effect. See Signing keys. - The private key protector must actually encrypt. With automatic management, pass in your own
dp.DataProtectionProvider(such as AES-GCM), with the master key coming from your key management system and identical on all replicas. Wicket's built-in default data protection implementation is not suitable for production. - Retention covers token lifetimes.
RetentionDuration(default 14 days) should be no shorter than the longest token lifetime plus clock skew; the same applies to manual rotation, where old public keys must stay in JWKS long enough. - Keep signing private keys out of the code repository and images; deliver them through mounted key files or a KMS.
Data protection (known limitation)
- Understand the limits of the built-in data protection. The default
DataProtectionProviderbuilt into the v0.1.4 container is not suitable for production, and the container doesn't yet provide an injection point to replace it globally (KeyManagement.Protectorapplies only to the key manager; external login schemes can pass in their own implementation separately as described in External login). It is used for Wicket's message cookies, interaction contexts such as errors and logout, and external login state; in addition, persisted grant data is not protected in v0.1.4 (PersistentGrants.DataProtectDatahas no effect). Until a fixed version provides a way to replace it:- Apply access control and encryption at rest to the database that stores grant data;
- Don't assume these payloads are confidential in the database or in the browser.
Cleanup and background tasks
- Run an expired-data cleanup loop (host responsibility). Wicket starts no background goroutines. The host periodically calls each store's
RemoveExpiredand the session store'sDeleteExpired; see Persistence for an example. - On shutdown, stop the cleanup loop first, then call
root.Close().
Multiple replicas
- All stateful seams point to shared storage (the same PostgreSQL, etc.).
- Signing keys (or the key record store + protector master key) are consistent across replicas.
IssuerUriis the same on all replicas.- Know the scope of the distributed cache: if you inject the in-memory
NewMemoryDistributedCache(), device code polling rate limits are computed per replica; implementservices.DistributedCacheyourself if you need global rate limiting. - Running the cleanup loop on multiple replicas is safe, but you can run it on only one replica to reduce database load.
Logging
- Host code must not log tokens, authorization codes, refresh tokens, client secrets, or signing private keys; log only identifiers or prefixes. Request logging middleware must skip the
Authorizationheader and the token endpoint's request body. - Filter Wicket's internal logs on the log collection side. In v0.1.4 the container's internal logger is fixed at
NewRoot()time to JSON format, Debug level, written to standard output;cfg.SetLoggerdoesn't change it, and the host currently cannot adjust its level. These logs are high-volume, and some of them may contain sensitive request parameters. On the collection side, drop Debug bylevel, remove sensitive fields, restrict access, and avoid sending raw logs to untrusted systems. See Logging and observability for details. - Strip passwords from connection strings such as DSNs before logging them.
Browsers and cross-origin
- CORS is handled by the host. v0.1.4 has no code that emits
Access-Control-*response headers, andCorsOptionsandClient.AllowedCorsOriginsproduce no CORS behavior on their own (they can serve as decision data for host middleware). If a single-page app calls the token, UserInfo, discovery, or JWKS endpoints directly from the browser, add your own CORS middleware outside Wicket and strictly limit the allowed origins; see CORS. - Set
UserInteraction.LoginUrlandLoginReturnUrlParameter(both empty by default), and provide a cookie handler for thewicketauthentication scheme. The login page accepts only a same-site relativereturnUrl, to prevent open redirects. - Make sure
ErrorUrl(default/home/error) andConsentUrl(default/consent) point to pages that actually exist in the host.
Endpoints and feature surface
- Turn off discovery advertising for unimplemented endpoints:
Endpoints.EnableTokenRevocationEndpointandEnableDeviceAuthorizationEndpointdefault totrue, which makes the discovery document advertise/connect/revocationand/connect/deviceauthorization, which don't exist in v0.1.4. - Block unused endpoints as needed.
EnableTokenEndpoint,EnableAuthorizeEndpoint,EnableIntrospectionEndpoint, andEnableBackchannelAuthenticationEndpointonly affect the discovery document and don't stop the endpoints from working; to block them, intercept the paths in an outer middleware. - The
passwordgrant is rejected by default; inject aResourceOwnerPasswordValidatoronly if you really need it. - Store client secrets hashed with
utils.Sha256. To rotate, configure both the old and newSecretat the same time, and remove the old secret from the configuration once the switch is complete. In v0.1.4, don't setExpirationon secrets; see Client credentials. - Keep
RequirePkce = trueandAllowPlainTextPkce = falsefor public clients (SPAs, mobile apps).
Startup and shutdown
- Do all wiring during startup, so that the panics from
Freeze()andUseWicket()make configuration errors fail at deployment time (pair this with a readiness probe). - Don't modify
WicketOptionsorServerConfigwhile the service is running. - Shutdown order:
http.Server.Shutdown→ stop the cleanup loop →root.Close()→ close the connection pool.
Versions
- Pin exact versions:
github.com/gonewx/wicket v0.1.4,github.com/gonewx/wicket-pg v0.1.3(which depends on wicket v0.1.4). Incompatible changes may occur during v0.x; read the Changelog before upgrading. - Build with the Go 1.27 toolchain.