Broken API authorization hands an attacker a valid session without stealing a password. CompTIA SecurityX (CAS-005) treats that failure as an architecture and engineering problem: objective 2.5 requires API authorization, logging, and rate limiting; objective 2.6 requires continuous authorization and explicit subject-object relationships; objective 3.1 requires you to operate Open Authorization (OAuth) and to rotate and delete tokens as secrets. This article maps those objectives onto the IETF OAuth 2.0 protocol so you can choose a grant type and harden the tokens it issues. For the full CAS-005 domain map, use the ultimate guide to CompTIA SecurityX (CAS-005).
What OAuth 2.0 Actually Authorizes
OAuth 2.0 is a delegated-authorization framework, not a login protocol. RFC 6749 defines it so a third-party client can obtain limited access to an HTTP service without receiving the resource owner’s password.
Four roles move the data:
- Resource owner — the user or service that owns the data.
- Client — the application that wants access. Confidential clients can keep a client_secret. Public clients (native apps, many single-page apps) cannot.
- Authorization server (AS) — authenticates the owner, obtains consent, and issues tokens.
- Resource server (RS) — the API that accepts a token and returns protected resources.
The client never presents the user’s password to the API. The client presents an access token. The resource server validates that token and enforces scope. That split is the subject-object relationship CAS-005 2.6 asks you to define: the subject is the client acting for a user or for itself; the object is the API resource; the authorization decision lives on the authorization server and is re-checked on every call.
OAuth issues three credentials you must treat as secrets under CAS-005 3.1 (tokens, rotation, deletion):
- Authorization code — a short-lived, one-time credential that the client exchanges at the token endpoint.
- Access token — the credential the client sends to the API. RFC 6750 defines the Bearer usage: Authorization: Bearer <token> over TLS. Do not put the token in a URI query string; servers log URLs.
- Refresh token — a longer-lived credential the client sends only to the authorization server to mint a new access token.
OpenID Connect sits next to OAuth on the CAS-005 3.1 list. OAuth answers “what may this client do?” OpenID Connect adds an ID token that answers “who authenticated?” Do not use an access token as proof of identity unless your design explicitly requires that and the token audience matches the verifier.
The Four RFC 6749 Grant Types
RFC 6749 defines four authorization grants plus an extension mechanism. A grant is the proof the client presents to the token endpoint. Pick the grant that matches how the client can authenticate and whether a human is present.
Authorization code
The client redirects the resource owner’s user-agent to the authorization endpoint. The owner authenticates and consents at the authorization server. The server redirects back to a pre-registered redirect_uri with a code and the original state value. The client then POSTs that code to the token endpoint, authenticates as itself if it is confidential, and receives tokens on the back channel.
That back-channel exchange is the security property. The browser never sees the access token. The authorization server can authenticate the client. The code is single-use.
Use this grant for web apps, native apps, and browser-based apps. Pair it with PKCE in every new design (next section). RFC 9700 tells authorization servers to compare redirect_uri values with exact string matching, except for the port on native-app localhost URIs.
Authorization request (front channel):
http
GET /authorize?response_type=code
&client_id=web-portal
&redirect_uri=https://app.example.com/cb
&scope=invoices.read
&state=x7K91p
&code_challenge=E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM
&code_challenge_method=S256
Host: as.example.com
Token request (back channel):
http
POST /token HTTP/1.1
Host: as.example.com
Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW
Content-Type: application/x-www-form-urlencoded
grant_type=authorization_code
&code=SplxlOBeZQQYbYS6WxSbIA
&redirect_uri=https://app.example.com/cb
&code_verifier=dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk
Implicit
The implicit grant returns the access token in the redirect URI fragment (response_type=token). RFC 6749 designed it for in-browser clients that could not keep a secret. The token travels on the front channel. It lands in browser history, Referer headers, and intermediary logs. The flow does not issue refresh tokens.
RFC 9700 Section 2.1.2 says clients SHOULD NOT use the implicit grant or any response type that issues access tokens in the authorization response. Use response_type=code instead. RFC 10017 repeats the same rule for browser-based applications: the authorization server MUST issue access tokens only from the token endpoint.
Treat implicit as a legacy compatibility mode, not a SecurityX design choice.
Resource owner password credentials (ROPC)
The client collects the user’s username and password and POSTs them to the token endpoint as grant_type=password. RFC 6749 already limited this grant to highly trusted first-party clients when no other grant works.
RFC 9700 Section 2.4 is unambiguous: the resource owner password credentials grant MUST NOT be used. It hands the owner’s password to the client, widens the leak surface, trains users to type passwords into the wrong origin, and blocks modern MFA and WebAuthn.
If a first-party mobile app still uses ROPC, migrate it to authorization code with PKCE so the authorization server owns the authentication ceremony.
Client credentials
The client authenticates as itself and receives an access token for resources it owns or that an administrator pre-approved. No human is in the loop. RFC 6749 defines this grant for machine-to-machine calls: batch jobs, service meshes, CI pipelines talking to an API.
http
POST /token HTTP/1.1
Host: as.example.com
Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW
Content-Type: application/x-www-form-urlencoded
grant_type=client_credentials&scope=backup.execute
Harden this grant at the secret, not at the user. Store the client_secret or private key in a secrets manager. Rotate it. Delete it when the workload dies. That is CAS-005 3.1 secrets management applied to a non-human subject. Bind the token audience to one API. Do not reuse a client-credentials token across unrelated resource servers.
A fifth common grant_type is refresh_token. It is not one of the original four owner-authorization grants. It is how a client replaces an expired access token without repeating the consent redirect.
PKCE: Bind the Code to the Client That Requested It
Proof Key for Code Exchange (PKCE, RFC 7636) stops an attacker who steals the authorization code from exchanging it. The client creates a high-entropy code_verifier (43–128 unreserved characters). It sends code_challenge = BASE64URL(SHA-256(ASCII(code_verifier))) on the authorize request with code_challenge_method=S256. At the token endpoint it sends the raw code_verifier. The authorization server hashes that verifier and compares it to the stored challenge. A stolen code is useless without the verifier.
RFC 7636 wrote PKCE for public clients. RFC 9700 widened the rule:
- Public clients MUST use PKCE.
- Confidential clients SHOULD use PKCE; it blocks authorization-code injection and also covers CSRF when state handling fails.
- Authorization servers MUST support PKCE.
- If the client can use S256, it MUST use S256. plain exists only for legacy constraints.
That is why authorization code plus PKCE is the 2026 default for every interactive client, including single-page apps. The implicit grant’s original justification — “the browser cannot keep a secret” — no longer excuses putting tokens in the URL. PKCE does not require a client_secret. It requires a per-request verifier the attacker does not have.
Token Hardening
A correct grant still fails if the token is long-lived, replayable, or stored like a config string. CAS-005 3.1 lists tokens next to keys and passwords and requires rotation and deletion. Apply those controls on both token types.
Issue access tokens for minutes, not hours. The resource server must reject an expired token. Short lifetime limits the window after theft. The client uses the refresh token to mint a replacement.
Rotate refresh tokens. RFC 9700 Section 4.14.2 describes rotation: every refresh response issues a new refresh token and invalidates the previous one. If both the attacker and the real client present tokens, one of them submits a revoked token. The authorization server revokes the family and forces a new authorization grant. Refresh tokens for public clients MUST be sender-constrained or rotated.
Sender-constrain access tokens. A Bearer token is valid for whoever holds it. RFC 9700 Section 2.2.1 says authorization and resource servers SHOULD sender-constrain access tokens with mutual TLS for OAuth 2.0 (RFC 8705) or Demonstrating Proof-of-Possession (DPoP, RFC 9449). mTLS binds the token to the client certificate. DPoP binds the token to a client key; the client signs a proof JWT on each API call. A leaked token then fails at the resource server because the thief lacks the key.
Restrict audience and scope. Mint each access token for one resource server (aud) and the smallest scope the call needs. A token minted for the billing API must fail at the admin API. That is Zero Trust subject-object design (CAS-005 2.6) encoded in the token.
Put tokens only where 3.1 can rotate and delete them. Confidential-client secrets and refresh tokens belong in a secrets manager or an OS-protected store, not in source control, container environment dumps, or browser localStorage if an XSS payload can read it. Delete tokens on logout, on client deprovisioning, and when a refresh-family revoke fires. Log the deletion.
Never send Bearer tokens in query strings. RFC 6750 Section 2.3 allows a query parameter only when the header and body are impossible, and it warns that URLs get logged. Use the Authorization header over TLS. TLS is mandatory for Bearer use.
Match redirect URIs exactly. Open redirectors and wildcard redirect URIs turn the authorization code into a stealable object. RFC 9700 requires exact string matching at the authorization server.
API Security Controls That sit in Front of the Token
CAS-005 2.5 names three API-security bullets: authorization, logging, and rate limiting. They are not optional decorations on an OAuth deployment.
Authorization at the resource server. Valid signature and unexpired exp are not enough. The resource server checks aud, scope, the HTTP method, and the object identifier. Continuous authorization (CAS-005 2.6) means that check runs on every request, not once at login. Context-based reauthentication belongs here: step-up when the subject asks for a higher-privilege object.
Logging. Log token issuance, refresh, revocation, failed PKCE verification, redirect_uri mismatch, and API authorization denials. Do not log raw access tokens or authorization codes. Log a hash or a token identifier. Those events feed the IAM troubleshooting work in objective 3.1.
Rate limiting. Throttle the authorize endpoint, the token endpoint, and every authenticated API route. Credential stuffing and code-guessing die at the token endpoint. Stolen-token replay dies at the API when you combine rate limits with sender-constrained tokens and short lifetimes.
Place those three controls on the API gateway or the resource server itself. An API gateway that only checks “is there a Bearer header?” has not implemented 2.5 authorization.
Exam-ready Decision Path
When a CAS-005 scenario puts an API, a client type, and a token on the table, walk this path:
- Name the subject and the object (2.6). User-delegated access uses authorization code plus PKCE. Workload-to-API access uses client credentials plus a managed secret or a workload identity.
- Reject implicit and resource-owner-password grants for new designs (RFC 9700).
- Treat every token as a 3.1 secret: short access-token lifetime, refresh rotation or sender constraint, explicit deletion.
- Enforce 2.5 on the API: authorize the scope against the object, log the decision, rate-limit the endpoints that issue and consume tokens.
OAuth 2.0 does not make an API safe. The grant type selects the channel. PKCE binds the code. Token hardening and API controls decide whether a stolen credential still opens the object.
Leave a Reply