Client Types
Confidential clients
Section titled “Confidential clients”A confidential client can securely store a secret — typically a server-side application where the secret is never exposed to the browser.
client_type:confidential- Authenticates at the token endpoint using a
client_secret - Two authentication methods:
client_secret_basic: form-encoded credentials in theAuthorization: Basicheaderclient_secret_post: credentials in the POST body asclient_idandclient_secretform fields
Token exchange example (Basic auth):
curl -X POST https://auth.example.com/oauth2/token \ -u "my-client-id:my-client-secret" \ -H "Content-Type: application/x-www-form-urlencoded" \ -d "grant_type=authorization_code" \ -d "code=AUTH_CODE" \ -d "redirect_uri=https://app.example.com/callback" \ -d "code_verifier=CODE_VERIFIER"Credential encoding and transport
Section titled “Credential encoding and transport”For OAuth Basic authentication, form-encode client_id and client_secret separately, join the encoded values with a colon, then Base64-encode the result (RFC 6749 §2.3.1). The server reverses that form encoding exactly once. For example, a literal + becomes %2B, % becomes %25, : becomes %3A, and a space becomes +. This matters for custom IDs or secrets; client libraries must prepare OAuth Basic credentials rather than passing raw reserved characters.
Form authentication sends credentials only in the POST body. Non-empty credentials in URL parameters are rejected. Empty parameters are treated as omitted, as required by RFC 6749 §3.2 and RFC 8628 §3.1. Use one authentication method per request: do not combine Basic with a form secret or another Authorization header. A redundant body client_id is allowed only when it matches the decoded Basic identity.
Invalid body/URI transports, duplicate parameters and conflicting credentials return 400 invalid_request. Wrong or malformed Basic credentials return 401 invalid_client with a matching Basic challenge; malformed Basic never falls back to form credentials. These rules apply to token, device authorization, introspection and revocation requests. Admin bearer authentication remains available at introspection and revocation as a separate method.
Public clients
Section titled “Public clients”A public client cannot store a secret securely — a browser SPA or mobile app where any embedded secret would be visible.
client_type:publictoken_endpoint_auth_method:none- Must use PKCE — the
code_challenge/code_verifierpair substitutes for the client secret
No client_secret is issued for public clients.
Token exchange example (PKCE, no secret):
curl -X POST https://auth.example.com/oauth2/token \ -H "Content-Type: application/x-www-form-urlencoded" \ -d "grant_type=authorization_code" \ -d "code=AUTH_CODE" \ -d "redirect_uri=https://app.example.com/callback" \ -d "client_id=my-client-id" \ -d "code_verifier=CODE_VERIFIER"Summary
Section titled “Summary”| Confidential | Public | |
|---|---|---|
Has client_secret |
Yes | No |
| Auth method | client_secret_basic or client_secret_post |
none |
| PKCE required | Recommended | Required |
| Typical use case | Server-side apps, APIs | SPAs, mobile apps, CLIs |