Protocol endpoints
This page lists the HTTP endpoints that Wicket v0.1.4 actually handles, along with the methods they accept, how they authenticate, and what their error responses look like. All behavior is based on the source code (di/dsl_core.go, handlers/) and on testing the Quick start example.
Routing rules
Wicket mounts as middleware in front of the host handler:
handler := hosting.ScopeMiddleware(root)(srv.UseWicket()(app))On each incoming request, the router compares r.URL.Path against the registered endpoint paths as a whole-string, case-insensitive match:
- Match → the corresponding handler processes it, and the host's
appisn't called; - No match → the request is passed to the host's
appunchanged.
You must wrap it in ScopeMiddleware
UseWicket() relies on the scope that hosting.ScopeMiddleware(root) puts into the request context. Without that layer, the Wicket middleware passes every request straight through to the host without any error—every endpoint turns into the host's 404 or home page.
When a handler hits a failure that can't be mapped to a protocol error (for example a storage error), the middleware responds with HTTP 501 and a plain-text error message (hosting/middleware.go). In production, wrap the host in an outer recovery and logging middleware, and keep in mind that this error text may contain internal details.
Registered endpoints
The table below corresponds one-to-one to the 11 hosting.Endpoint registrations in di/dsl_core.go.
| Path | Method | Purpose | Notes |
|---|---|---|---|
/connect/authorize | GET; POST (form) | Entry point for authorization requests | POST must be application/x-www-form-urlencoded, otherwise 415. On parameter errors, 302 to the host's error page (default /home/error?errorId=...) |
/connect/authorize/callback | GET | Where the user returns after interacting with the login/consent page, to resume the original authorization request | Non-GET returns 405 |
/connect/token | POST (form) | Token endpoint | See "Supported grant types" and "Client authentication methods" below. v0.1.4 doesn't check the method: GET/PUT also reach the processing logic, and in testing return 400 invalid_request |
/.well-known/openid-configuration | GET | Discovery document | Non-GET returns 405; 404 when Endpoints.EnableDiscoveryEndpoint=false. See Discovery document |
/.well-known/openid-configuration/jwks | GET | JWKS public key set | Non-GET returns 405; 404 when EnableDiscoveryEndpoint or Discovery.ShowKeySet is false |
/connect/userinfo | GET, POST | User info | Requires a Bearer access token; 401 with no token or an invalid token, 403 when the token lacks the openid scope |
/connect/introspect | POST (form) | Token introspection (RFC 7662) | The caller authenticates with an API resource name + API secret; any failure is 401 with no body; non-form 415; non-POST 405 |
/connect/endsession | GET; POST (form) | RP-initiated logout | Non-form POST 415, other methods 405 |
/connect/endsession/callback | GET | Renders the front-channel logout page after logout completes | Non-GET 405 |
/connect/checksession | GET | The check-session iframe for OIDC session management | Returns HTML with a CSP header |
/connect/ciba | POST (form) | CIBA backchannel authentication request | On success returns auth_req_id, expires_in (and optionally interval) |
Some endpoints are controlled by WicketOptions.Endpoints switches (returning 404 when turned off): userinfo, endsession, endsession/callback, checksession, discovery, jwks. The authorize, token, introspect, and ciba handlers don't read these switches—setting EnableTokenEndpoint and the like to false only removes them from the discovery document; requests are still processed.
URLs that appear in the discovery document but aren't registered
constants.go also defines the following path constants, and the discovery document advertises several of these URLs by default, but v0.1.4 registers no handler for them:
| Path | Discovery document field | Actual behavior |
|---|---|---|
/connect/revocation | revocation_endpoint | The request falls through to the host handler; Wicket doesn't handle it |
/connect/deviceauthorization | device_authorization_endpoint | Same as above |
/connect/mtls/token, /connect/mtls/revocation, /connect/mtls/introspect, /connect/mtls/deviceauthorization | mtls_endpoint_aliases (only present when MutualTls.Enabled=true) | Same as above |
Observed (Quick start example, with the host home page returning host app):
POST /connect/revocation → 200 host app
POST /connect/deviceauthorization → 200 host app
POST /connect/mtls/token → 200 host appTurn off advertisements for endpoints that don't exist
Token revocation and device authorization requests aren't handled by Wicket in v0.1.4. If your host returns 200 for unknown paths, clients may even believe a revocation succeeded. Turn off these two advertisements during wiring:
opts.Endpoints.EnableTokenRevocationEndpoint = false
opts.Endpoints.EnableDeviceAuthorizationEndpoint = falseNote that the second setting also removes urn:ietf:params:oauth:grant-type:device_code from grant_types_supported, but doesn't disable the token endpoint's handling of that grant type. For the current state of the device flow, see Device authorization.
Supported grant types
The token endpoint dispatches on grant_type (validators/impl/token_request_validator.go):
grant_type | Available by default | Description |
|---|---|---|
authorization_code | Yes | Authorization code + PKCE; the plain method is accepted only when the client has AllowPlainTextPkce=true (default false); stick with S256 |
client_credentials | Yes | Machine to machine |
refresh_token | Yes | Renew with a refresh token (v0.1.4 doesn't rotate them; see Refresh tokens); concurrent refresh conflicts return invalid_grant |
urn:ietf:params:oauth:grant-type:device_code | Yes (token endpoint side) | v0.1.4 has no built-in device authorization endpoint; device codes must be issued by the host itself |
urn:openid:params:grant-type:ciba | Yes | Used together with /connect/ciba |
password | No | The default validator NotSupportedResourceOwnerPasswordValidator always rejects; inject an implementation with cfg.SetResourceOwnerValidator(...) |
| Other values | No | Goes to the extension grant branch; v0.1.4's ServerConfig provides no method to register extension grant validators, and in testing it returns unsupported_grant_type |
Whatever the grant type, the client must also declare it in AllowedGrantTypes; otherwise the result is unauthorized_client. The implicit in the discovery document refers to flows such as response_type=token on the authorization endpoint, not a token endpoint grant_type.
Client authentication methods
The container registers only two secret parsers (di/dsl_core.go) and one secret validator:
| Discovery document name | Parser | Where it reads from |
|---|---|---|
client_secret_basic | BasicAuthenticationSecretParser | Authorization: Basic base64(client_id:client_secret) |
client_secret_post | PostBodySecretParser | Form fields client_id / client_secret; requires Content-Type: application/x-www-form-urlencoded |
The shared secret parsed by either is handed to HashedSharedSecretValidator for comparison: when the client is registered, Secret.Value stores a hash (the example uses utils.Sha256("change-me")), while the request carries the plaintext.
A request that carries only client_id and no secret is parsed as NoSecret, which applies only to public clients with RequireClientSecret=false.
v0.1.4 has no parsers for private_key_jwt, client_secret_jwt, or mTLS client authentication. MutualTls.Enabled=true only adds entries such as tls_client_auth to the discovery document; it doesn't actually enable certificate authentication—don't turn it on.
Success responses
On success, the token endpoint returns application/json with Cache-Control: no-store and Pragma: no-cache:
{
"access_token": "eyJhbGciOiJSUzI1NiIs...",
"expires_in": 3600,
"id_token": "",
"refresh_token": "",
"scope": "orders.read",
"token_type": "Bearer"
}The id_token and refresh_token keys are always present; when not issued, their value is an empty string (rather than the field being omitted). If a client library decides whether there's a refresh token based on "whether the field exists", change it to check for a non-empty value.
Error responses
Token endpoint
Observed shape (wrong client secret):
HTTP/1.1 400 Bad Request
Content-Type: text/plain; charset=utf-8
{"custom":{},"error":"invalid_client","error_description":""}Points to note, all describing v0.1.4 as it stands:
- Besides the standard
erroranderror_description, acustomobject is always included (custom response fields from the validator, usually an empty{}). error_descriptionis usually an empty string rather than omitted.- All token errors are 400, including
invalid_client(RFC 6749 recommends 401 for failed Basic authentication). - The response headers lack
Content-Type: application/jsonandCache-Control: no-store: the error result sets headers only after writing the status code, so those headers are dropped, andContent-Typeis sniffed astext/plainby the Go standard library. Clients should handle errors by status code + parsing the body, and not rely onContent-Type.
Other endpoints
| Scenario | Response |
|---|---|
| Parameter errors on CIBA or introspection requests | 400, body {"error":...,"error_description":...}, without a custom field |
| userinfo: invalid token / insufficient scope | 401 / 403, empty body. The source intends to write a WWW-Authenticate header, but again because headers are set after the status code, the header doesn't appear in observed responses |
| Introspection caller authentication fails | 401, empty body |
| Method not allowed / unsupported media type / endpoint disabled | 405 / 415 / 404, empty body |
| authorize parameter errors | 302 to the host's error page, with error details passed via errorId |