Coder powers secure, scalable development across key industries — automotive, finance, government, and technology — enabling faster builds, tighter compliance, and seamless AI adoption in enterprise-grade cloud environments.
This page covers how a client proves who it is and completes a login: the supported ways to prove identity, the standard login steps, the required PKCE (Proof Key for Code Exchange) step, and how a client finds the right web addresses to use.
OAuth2 provider: turn on the provider and create an application
Scopes: control what a client is allowed to access
Coder supports the following OAuth2 client authentication methods at the token endpoint (/oauth2/tokens):
client_secret_basic (recommended): HTTP Basic authentication (RFC 6749 §2.3.1). The username is client_id and the password is client_secret.
client_secret_post: Form-based authentication where client_id and client_secret are sent in the request body.
none: No client secret.
The client is a public client and authenticates with PKCE alone (RFC 7591 §2, OAuth 2.1 §2.1).
Available only through Dynamic Client Registration, which is disabled by default, since a client's type is set when it registers and apps created through the admin UI or API are always confidential.
Coder supports both methods, so existing integrations using client_secret_post don't need to switch to client_secret_basic.
Send client_secret in the request body or in the Authorization header.
POST /oauth2/tokens and POST /oauth2/revoke reject a client_secret value in the URL query string with invalid_request, because OAuth 2.1 section 2.4.1 does not allow it there.
Refer to "invalid_request" for client_secret in the query string for the exceptions and the log line to search for.
Public clients suit native, mobile, and CLI applications that cannot keep a secret confidential. Note the redirect URI restrictions below before choosing one.
Opening a public client on the OAuth2 Applications page shows no client secrets section, since a public client has no secret to display or generate.
If you use Dynamic Client Registration (RFC 7591) and omit token_endpoint_auth_method, clients default to client_secret_basic. To request client_secret_post, set token_endpoint_auth_method to client_secret_post in the registration request. To register a public client, set it to none: Coder issues no client_secret, and the registration response omits that field entirely.
Important
Which redirect URI schemes and hosts a client may register, including the loopback host and port rules for public and confidential clients, is a separate restriction from client authentication.
Refer to Callback URL schemes.
A client's type is fixed when it registers.
An RFC 7592 update that would move a client between public and confidential is rejected with invalid_client_metadata, since the client either holds a secret that would stop being required or has none and no way to be issued one.
Switching between client_secret_basic and client_secret_post is allowed, because both are confidential.
To change type, register a new client.
Clients registered with token_endpoint_auth_method: none before Coder honored it are stored as confidential and still require their client_secret.
Coder reports client_secret_basic for those clients so that what it reports matches what it enforces, and the mismatch clears the next time the client updates its registration using the value Coder reported.
If client authentication fails, the token endpoint returns HTTP 401 with an OAuth2 invalid_client error and a WWW-Authenticate: Basic realm="coder" response header.
Authorization code flow
Every authorization code flow requires PKCE (Proof Key for Code Exchange).
Coder enforces PKCE in compliance with the OAuth 2.1 specification, for both public and confidential clients.
Note
code_verifier and code_challenge must each be 43-128 characters from the unreserved character set [A-Za-z0-9-._~] (RFC 7636 §4.1).
A value outside these bounds is rejected with an invalid_request error, at the token endpoint for code_verifier and at the authorization endpoint for code_challenge.
Send client_id in the form body and omit client_secret entirely.
The code verifier is the only proof of possession, and must satisfy RFC 7636 §4.1 (43-128 characters from [A-Za-z0-9-._~]).
Send the access token in the Authorization header.
Coder ignores an OAuth2 access token in the URL query string, as OAuth 2.1 section 5.1 requires.
This endpoint requires a signed-in user, so it answers HTTP 401.
Refer to HTTP 401 for an access token in the query string for endpoints that behave differently.
Discovery endpoints
Coder provides OAuth2 discovery endpoints for programmatic integration:
Authorization Server Metadata: GET /.well-known/oauth-authorization-server
Protected Resource Metadata: GET /.well-known/oauth-protected-resource
These endpoints return server capabilities and endpoint URLs according to RFC 8414 and RFC 9728.
token_endpoint_auth_methods_supported lists every method the token endpoint accepts, including none.
It is not gated on Dynamic Client Registration, since existing public clients still exchange tokens when new registrations are disabled.
registration_endpoint is advertised only while Dynamic Client Registration is enabled, so that field, not this one, tells a client whether it can register a new public client.
Standards compliance
This implementation follows established OAuth2 standards including RFC 6749 (OAuth2 core), RFC 7636 (PKCE), and the OAuth 2.1 draft.
Coder enforces OAuth 2.1 requirements including mandatory PKCE for all authorization code grants, exact redirect URI string matching with the RFC 8252 loopback port exception, rejection of the implicit grant, and CSRF protections on consent pages.