This chapter covers OAuth 2.0 and SSO attacks, a critical topic for the PT0-002 exam under Domain 3 (Attacks and Exploits), Objective 3.2. These attacks exploit weaknesses in authentication and authorization frameworks, and they appear in approximately 10-15% of exam questions. Understanding the underlying mechanisms and common misconfigurations is essential for both the exam and real-world penetration testing.
Jump to a section
Imagine you are a guest at a large hotel (the resource owner). You want to let a housekeeper (the client application) clean your room (access your protected resource). You do not want to give the housekeeper your personal room key (your password) because that would let them enter your room anytime, even after you check out. Instead, you go to the front desk (the authorization server) and request a special magnetic key card (an access token) that only works for the next two hours (token expiration) and only opens your room door (scope-limited). The front desk verifies your identity (authentication) and gives you the key card. You then hand that key card to the housekeeper. The housekeeper uses it to open your room once, and after two hours the card stops working. Even if the housekeeper tries to use the card later, the lock rejects it. Additionally, the card cannot open any other rooms—it is scoped to your room only. If the housekeeper loses the card, the damage is limited because the card expires and has restricted access. This is exactly how OAuth 2.0 works: the resource owner authenticates once with the authorization server, receives a token, and delegates limited access to a client without sharing long-term credentials.
What is OAuth 2.0 and Why It Exists
OAuth 2.0 is an authorization framework that enables third-party applications to obtain limited access to a user's resources without exposing the user's credentials. Defined in RFC 6749, it separates the role of the resource owner (user) from the client (application) and the authorization server. This separation is critical for security: the client never sees the user's password, and access can be scoped and revoked independently.
How OAuth 2.0 Works Internally
The core flow involves four roles: - Resource Owner: The user who owns the data. - Client: The application requesting access. - Authorization Server: Issues tokens after authenticating the resource owner. - Resource Server: Hosts the protected resources and validates tokens.
The most common flow is the Authorization Code Grant, which works as follows:
1. The client redirects the user to the authorization server with parameters: response_type=code, client_id, redirect_uri, scope, and state.
2. The user authenticates and consents to the requested scopes.
3. The authorization server redirects back to the client with an authorization code in the query string.
4. The client exchanges this code for an access token by making a POST request to the token endpoint with grant_type=authorization_code, code, redirect_uri, and client_secret.
5. The authorization server returns an access token (and optionally a refresh token).
6. The client uses the access token to request resources from the resource server.
Key Components, Values, and Defaults
Access Token: A string representing authorization. Often a JSON Web Token (JWT) containing claims like iss, sub, exp, scope. Default lifetime is typically 3600 seconds (1 hour) but configurable.
Refresh Token: A long-lived token (default 30 days) used to obtain new access tokens without user interaction.
Authorization Code: Short-lived (typically 60 seconds) and single-use.
Client ID: Public identifier for the client.
Client Secret: Confidential key used by the client to authenticate to the authorization server. Must be kept secret on server-side applications.
Redirect URI: Pre-registered URI where authorization codes are sent. Must match exactly; any mismatch is a security violation.
Scope: Defines the specific permissions requested (e.g., openid, profile, email, read, write).
State Parameter: A nonce-like value that prevents CSRF attacks on the authorization flow.
Configuration and Verification Commands
While OAuth 2.0 is not a command-line protocol, penetration testers often use tools like Burp Suite, Postman, or custom scripts to test implementations. For example, testing an OAuth endpoint with curl:
# Step 1: Get authorization code (user interaction required, simulate via browser)
# Step 2: Exchange code for token
curl -X POST https://auth.example.com/token \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=authorization_code&code=abc123&redirect_uri=https://client.example.com/callback&client_id=myclient&client_secret=secret"Response:
{
"access_token": "eyJhbGciOiJSUzI1NiIs...",
"token_type": "Bearer",
"expires_in": 3600,
"refresh_token": "def456",
"scope": "read write"
}How It Interacts with Related Technologies
OpenID Connect (OIDC): Built on top of OAuth 2.0, OIDC adds an identity layer. It introduces an ID token (JWT) that contains user identity claims. The flow is similar but includes the openid scope.
SAML: An older XML-based SSO protocol. OAuth 2.0 is more modern and used for APIs, while SAML is often used for web-based SSO.
JWT: Access tokens are often JWTs, allowing stateless validation by the resource server.
OAuth 2.0 Attacks
#### Authorization Code Interception
If an attacker can intercept the authorization code (e.g., via an insecure redirect URI or a man-in-the-middle attack), they can exchange it for an access token. The redirect_uri must be strictly validated; any open redirect vulnerability can be exploited.
#### CSRF on Authorization Code Flow
Without the state parameter, an attacker can trick a user into authorizing a malicious client. The state parameter binds the request to the user's session.
#### Token Theft and Replay If an access token is stolen (e.g., via XSS, insecure storage, or network sniffing), the attacker can use it until it expires. Using HTTPS is mandatory.
#### Implicit Grant Weaknesses The implicit grant returns the access token directly in the URL fragment, increasing exposure. It is deprecated in OAuth 2.1 and should not be used.
#### Client Secret Leakage In public clients (e.g., mobile apps, SPAs), client secrets cannot be stored securely. The PKCE (Proof Key for Code Exchange) extension mitigates this by replacing the secret with a dynamically generated code verifier.
SSO Attacks
Single Sign-On (SSO) allows users to authenticate once and access multiple applications. Common SSO implementations include OAuth 2.0 + OIDC, SAML, and Kerberos.
#### SAML Attacks - XML Signature Wrapping: Manipulating the SAML assertion while keeping the signature valid. - Replay Attacks: Reusing a valid SAML response within its validity window. - Identity Provider Confusion: Tricking the service provider into accepting an assertion from a malicious IdP.
#### OIDC Attacks
- Token Substitution: Swapping an ID token or access token from one user to another.
- Cross-Site Request Forgery (CSRF): Without the nonce parameter in the ID token, an attacker can reuse an authentication response.
- Unverified User Info: If the client does not validate the ID token's signature and issuer, an attacker can forge tokens.
#### Kerberos Attacks - Pass-the-Ticket: Stealing a Kerberos ticket and using it to authenticate as the victim. - Golden Ticket: Forging a Ticket Granting Ticket (TGT) with a compromised KRBTGT hash. - Silver Ticket: Forging a service ticket for a specific service.
Common Vulnerabilities in SSO Implementations
Improper Validation of Redirect URIs: Allows attackers to intercept codes or tokens.
Missing State/Nonce Parameters: Enables CSRF and replay attacks.
Weak Token Validation: Accepting tokens with incorrect signatures or expired timestamps.
Insecure Token Storage: Storing tokens in localStorage (vulnerable to XSS) instead of httpOnly cookies.
Overly Broad Scopes: Requesting more permissions than necessary increases risk.
Penetration Testing Techniques
Manual Inspection: Review the OAuth flow in Burp Suite, checking for missing state, open redirects, and token leakage in logs.
Automated Scanning: Use tools like OWASP ZAP's OAuth add-on or custom scripts to test for common misconfigurations.
Token Manipulation: Modify JWT tokens (e.g., change sub claim) and see if the server validates the signature.
Replay Attacks: Capture a valid token and replay it after a delay to see if the server checks exp.
OAuth 2.1 and PKCE
OAuth 2.1 (RFC 6749 bis) consolidates best practices and deprecates implicit grant and resource owner password credentials grant. PKCE is now required for all public clients. PKCE works as follows:
The client generates a random code_verifier (a high-entropy string, e.g., 43-128 characters).
The client computes a code_challenge = base64url(SHA256(code_verifier)).
The authorization request includes code_challenge and code_challenge_method=S256.
The token request includes code_verifier. The authorization server verifies that the challenge matches.
This prevents interception of the authorization code from being exchanged for a token, because the attacker does not know the code_verifier.
Exam-Relevant Numbers and Defaults
Authorization code lifetime: 60 seconds (typical)
Access token lifetime: 3600 seconds (1 hour, common default)
Refresh token lifetime: 30 days (common)
PKCE code verifier length: 43-128 characters
PKCE code challenge method: S256 (SHA-256) or plain
OAuth 2.0 RFC: 6749
OAuth 2.1: draft (deprecates implicit grant)
OIDC: built on OAuth 2.0, adds openid scope and ID token
User Initiates OAuth Flow
The client application redirects the user's browser to the authorization server's endpoint. The URL includes query parameters: `response_type=code` for authorization code grant, `client_id`, `redirect_uri`, `scope`, and `state`. The `state` parameter is a random value generated by the client to prevent CSRF. The user sees a login page and optionally a consent screen. The authorization server authenticates the user (e.g., via username/password) and records the user's consent to the requested scopes.
Authorization Code Issued
After successful authentication and consent, the authorization server generates a short-lived, single-use authorization code. It redirects the user's browser back to the `redirect_uri` with the code in the query string (e.g., `https://client.example.com/callback?code=abc123&state=xyz`). The code typically expires in 60 seconds. The client must verify that the `state` parameter matches the original value to prevent CSRF attacks.
Client Exchanges Code for Token
The client makes a server-to-server POST request to the authorization server's token endpoint. The request includes `grant_type=authorization_code`, `code`, `redirect_uri`, and `client_secret` (for confidential clients). For public clients, PKCE requires `code_verifier` instead of `client_secret`. The authorization server validates the code, checks it has not been used, and verifies the client credentials. If valid, it returns a JSON response containing `access_token`, `token_type`, `expires_in`, and optionally `refresh_token` and `scope`.
Client Accesses Resource Server
The client uses the access token to request protected resources from the resource server. It includes the token in the HTTP Authorization header as `Bearer <token>`. The resource server validates the token: it checks the signature (if JWT), expiration (`exp` claim), issuer (`iss`), and scopes (`scope`). If valid, it returns the requested data. The token may be cached by the client and reused until it expires. The resource server typically does not contact the authorization server for each request if the token is self-contained.
Token Refresh (Optional)
When the access token expires, the client can use the refresh token to obtain a new access token without user interaction. The client sends a POST request to the token endpoint with `grant_type=refresh_token` and `refresh_token`. The authorization server issues a new access token and optionally a new refresh token. Refresh tokens are long-lived (e.g., 30 days) and can be revoked. If the refresh token is stolen, the attacker can obtain new access tokens until the refresh token expires or is revoked.
Enterprise Scenario 1: Third-Party API Integration
A company uses Salesforce as its CRM and wants to integrate with a third-party analytics tool. The analytics tool needs read access to Salesforce data. Using OAuth 2.0, the company's admin authenticates to Salesforce (authorization server) and grants the analytics tool (client) access with the scope api. The tool receives an access token valid for 1 hour and a refresh token valid for 30 days. This setup ensures that the analytics tool never stores Salesforce credentials. If the integration is decommissioned, the admin can revoke the tokens from Salesforce. A common misconfiguration is using too broad a scope (e.g., full instead of api), giving the third-party tool excessive permissions.
Enterprise Scenario 2: SSO with OIDC
A large enterprise adopts Azure AD as its identity provider (IdP) for all internal applications. Employees log in once and access email (Exchange Online), file storage (SharePoint), and custom HR apps. Each application is an OIDC client that redirects to Azure AD for authentication. The ID token contains user claims like name, email, and employeeid. The access token is used to call Microsoft Graph API. A critical security consideration is token lifetime: if access tokens have a long lifetime (e.g., 24 hours), a stolen token can be used for a full day. The enterprise should configure token lifetime policies (e.g., 1 hour) and enforce device compliance before issuing tokens.
Enterprise Scenario 3: SAML SSO with On-Premises IdP
A university uses Shibboleth as its SAML IdP. Students log in once to access the learning management system (LMS), library resources, and email. The LMS (service provider) receives a SAML assertion containing the student's unique ID and attributes like role (e.g., 'student' or 'faculty'). A common attack is XML signature wrapping: the attacker modifies the assertion's content (e.g., changes the user ID) while keeping the signature valid by exploiting flaws in the XML parser. Another issue is replay: if the assertion's NotOnOrAfter condition is not validated, an attacker can reuse a captured assertion. The university must enforce short assertion lifetimes (e.g., 5 minutes) and use signed assertions with proper XML canonicalization.
What PT0-002 Tests on OAuth 2.0 and SSO Attacks
The exam focuses on identifying vulnerabilities in OAuth 2.0 and SSO implementations. Key objective codes: 3.2 (Attacks and Exploits), specifically covering token theft, CSRF, replay attacks, and misconfigurations. You must be able to recognize attack scenarios and recommend mitigations.
Common Wrong Answers and Why
'Use HTTPS to prevent all OAuth attacks' – HTTPS prevents network sniffing but does not prevent CSRF, token leakage in logs, or client secret exposure. The exam expects you to know that HTTPS is necessary but not sufficient.
'The implicit grant is the most secure because it does not expose the client secret' – The implicit grant is actually less secure because the token is exposed in the URL fragment and can be leaked via Referer headers, browser history, or logs. OAuth 2.1 deprecates it.
'Refreshing a token always requires the user to re-authenticate' – Refresh tokens allow silent refresh without user interaction. The exam tests that refresh tokens are long-lived and can be revoked.
'SAML is more secure than OAuth' – Both have vulnerabilities; the security depends on implementation. The exam expects you to know specific attacks for each (e.g., XML signature wrapping for SAML, CSRF for OAuth).
Specific Numbers and Terms on the Exam
Authorization code lifetime: 60 seconds
Access token default lifetime: 3600 seconds
PKCE code challenge method: S256
OAuth 2.0 RFC: 6749
OpenID Connect: adds ID token and openid scope
State parameter: prevents CSRF
Nonce: prevents replay in OIDC
Edge Cases and Exceptions
Redirect URI validation: The exam loves testing that the redirect URI must match exactly, including trailing slashes. A mismatch leads to token interception.
Token revocation: Refresh tokens can be revoked, but access tokens often cannot be revoked until they expire. The exam may ask about the impact of token theft.
Public vs. confidential clients: Public clients (SPAs, mobile apps) cannot securely store client secrets; PKCE is mandatory for them. The exam may test which clients require PKCE.
How to Eliminate Wrong Answers
Focus on the underlying mechanism. For example, if a question describes an attacker intercepting an authorization code, the mitigation is not just HTTPS (which protects the channel) but also PKCE (which protects against code interception even if the channel is compromised). If a question involves a replay attack, look for missing state or nonce. Always consider the specific grant type and client type.
OAuth 2.0 is authorization, not authentication; OIDC adds authentication.
Always use the authorization code grant with PKCE for public clients.
The state parameter is mandatory to prevent CSRF attacks.
Access tokens default to 3600 seconds (1 hour); refresh tokens default to 30 days.
HTTPS is necessary but not sufficient; implement token validation and short lifetimes.
SAML attacks include XML signature wrapping and replay; OAuth attacks include CSRF and token interception.
PKCE uses a code verifier (43-128 characters) and code challenge (S256 hashed).
Never store tokens in localStorage; use httpOnly cookies or secure storage.
Redirect URIs must be validated exactly, including trailing slashes.
Refresh tokens can be revoked; access tokens often cannot until expiration.
These come up on the exam all the time. Here's how to tell them apart.
OAuth 2.0 Authorization Code Grant
Uses a short-lived authorization code exchanged for token server-side.
Token never exposed in URL fragment; only in server-to-server communication.
Requires client secret or PKCE for public clients.
More secure; recommended for all clients.
Supports refresh tokens.
OAuth 2.0 Implicit Grant
Returns access token directly in URL fragment after user consent.
Token exposed in browser history, Referer headers, and server logs.
No client secret needed; no PKCE.
Less secure; deprecated in OAuth 2.1.
Does not support refresh tokens.
Mistake
OAuth 2.0 is an authentication protocol.
Correct
OAuth 2.0 is an authorization framework, not authentication. It delegates access to resources. OpenID Connect (OIDC) adds authentication on top of OAuth 2.0.
Mistake
The implicit grant is more secure than the authorization code grant because it does not expose the client secret.
Correct
The implicit grant is less secure because the access token is exposed in the URL fragment, making it vulnerable to Referer header leakage, browser history, and man-in-the-middle attacks. OAuth 2.1 deprecates it.
Mistake
Using HTTPS alone prevents all OAuth attacks.
Correct
HTTPS prevents network sniffing but does not prevent CSRF (missing state parameter), token leakage in server logs, XSS attacks that steal tokens, or client secret exposure in public clients.
Mistake
Refresh tokens are always short-lived like access tokens.
Correct
Refresh tokens are typically long-lived (e.g., 30 days) to allow silent re-authentication. They can be revoked, but if stolen, they pose a significant risk.
Mistake
SAML is inherently more secure than OAuth 2.0.
Correct
Both protocols have known vulnerabilities. SAML is vulnerable to XML signature wrapping and replay attacks; OAuth 2.0 is vulnerable to CSRF and token interception. Security depends on proper implementation.
Reveal each answer, then mark whether you got it right. Score 60%+ to unlock the next chapter.
OAuth 2.0 is an authorization framework that allows third-party applications to access resources on behalf of a user. OpenID Connect (OIDC) is an authentication layer built on top of OAuth 2.0. OIDC adds an ID token (a JWT containing user identity claims) and the `openid` scope. While OAuth 2.0 provides an access token for API access, OIDC provides identity verification. For the exam, remember that OIDC is for authentication; OAuth 2.0 is for authorization.
The implicit grant was deprecated because it exposes the access token in the URL fragment, increasing the risk of token leakage via browser history, Referer headers, and server logs. It also does not support refresh tokens or PKCE. The authorization code grant with PKCE is now recommended for all clients, including public clients like single-page applications.
PKCE (Proof Key for Code Exchange) is an extension to OAuth 2.0 that prevents authorization code interception attacks. The client generates a random code verifier (a high-entropy string of 43-128 characters) and sends a hash (code challenge) during the authorization request. When exchanging the code for a token, the client sends the original code verifier. The authorization server verifies that the verifier matches the challenge. An attacker who intercepts the authorization code cannot exchange it without the code verifier.
Without the `state` parameter, an attacker can trick a user into authorizing a malicious client. The attacker crafts a URL that redirects the user to the authorization server with the attacker's client ID. If the user authenticates and consents, the authorization code is sent to the attacker's redirect URI, allowing the attacker to obtain a token. The `state` parameter binds the authorization request to the user's session, preventing this attack.
A SAML replay attack occurs when an attacker captures a valid SAML response (assertion) and sends it again to the service provider within the assertion's validity window. To prevent this, the service provider must check the `NotOnOrAfter` condition and optionally use a `OneTimeUse` condition. Additionally, the assertion should include a unique ID and the service provider should maintain a cache of used assertion IDs.
A golden ticket is a forged Ticket Granting Ticket (TGT) that allows an attacker to impersonate any user in the domain. It requires the KRBTGT account hash. A silver ticket is a forged service ticket for a specific service, allowing access to that service without a TGT. Silver tickets require the service account's hash. Both are post-exploitation attacks in Active Directory environments.
Tokens should never be stored in localStorage or sessionStorage because they are accessible via JavaScript (XSS vulnerability). Instead, use httpOnly, Secure, SameSite cookies. The backend can set a cookie containing the token, which is automatically sent with requests. Alternatively, use the BFF (Backend for Frontend) pattern where the backend handles token storage and exchange, and the SPA only receives session cookies.
You've just covered OAuth 2.0 and SSO Attacks — now see how well it sticks with free PT0-002 practice questions. Full explanations included, no account needed.
Done with this chapter?