Skip to content

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, and ServerSideSessions.CookieSecure for the server-side session cookie already defaults to true.

  • Set IssuerUri explicitly, exactly matching the authority configured on clients and resources (including https://, with no trailing /). When it isn't set, the issuer changes with the request's Host, and token validation fails across different entry points.

  • Handle reverse-proxy headers (host responsibility). Wicket doesn't read X-Forwarded-* / Forwarded. IssuerUri only pins iss; the endpoint URLs in the discovery document are still derived from r.Host and r.TLS, so when TLS is terminated at the proxy they become http://<internal address>. You can add a middleware outside Wicket that trusts only your own proxy (tested on v0.1.4; the discovery document then outputs https://id.example.com/...):

    go
    func 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.Up in the startup sequence, and consider using ConformsTo() 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's NewKeyRecordStore).
  • When enabling automatic rotation, wire it the v0.1.4 way: build your own keymgmt.Manager and inject adapters; changing opts.KeyManagement has 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 DataProtectionProvider built 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.Protector applies 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.DataProtectData has 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 RemoveExpired and the session store's DeleteExpired; 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.
  • IssuerUri is 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; implement services.DistributedCache yourself 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 Authorization header 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.SetLogger doesn'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 by level, 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, and CorsOptions and Client.AllowedCorsOrigins produce 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.LoginUrl and LoginReturnUrlParameter (both empty by default), and provide a cookie handler for the wicket authentication scheme. The login page accepts only a same-site relative returnUrl, to prevent open redirects.
  • Make sure ErrorUrl (default /home/error) and ConsentUrl (default /consent) point to pages that actually exist in the host.

Endpoints and feature surface ​

  • Turn off discovery advertising for unimplemented endpoints: Endpoints.EnableTokenRevocationEndpoint and EnableDeviceAuthorizationEndpoint default to true, which makes the discovery document advertise /connect/revocation and /connect/deviceauthorization, which don't exist in v0.1.4.
  • Block unused endpoints as needed. EnableTokenEndpoint, EnableAuthorizeEndpoint, EnableIntrospectionEndpoint, and EnableBackchannelAuthenticationEndpoint only affect the discovery document and don't stop the endpoints from working; to block them, intercept the paths in an outer middleware.
  • The password grant is rejected by default; inject a ResourceOwnerPasswordValidator only if you really need it.
  • Store client secrets hashed with utils.Sha256. To rotate, configure both the old and new Secret at the same time, and remove the old secret from the configuration once the switch is complete. In v0.1.4, don't set Expiration on secrets; see Client credentials.
  • Keep RequirePkce = true and AllowPlainTextPkce = false for public clients (SPAs, mobile apps).

Startup and shutdown ​

  • Do all wiring during startup, so that the panics from Freeze() and UseWicket() make configuration errors fail at deployment time (pair this with a readiness probe).
  • Don't modify WicketOptions or ServerConfig while 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.

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