Series · 5 partsExternal Perimeter IntelligencePart 5 · You are here
- 1The External Perimeter Is a Graph. The Port List Is Only One View.
- 2The Domain Resolved. Ownership Was Still a Hypothesis.
- 3The Vendor Was Out of Scope. The Trust Boundary Was Not.
- 4The Service Was Observed. The Application Was Still Unknown.
- 5The Login Page Was Public. The Identity Boundary Was Somewhere Else.You are here
Identity boundary mapping in 60 seconds
A public application redirects the browser to an identity provider. The user signs in, returns to
/callback, and receives an application cookie. It is tempting to record “OIDC login” and move on.
But the visible login page is only the first frame of a longer authority decision.
The application must still decide:
- which issuer and client this response belongs to;
- whether the callback belongs to the flow that this browser started;
- which token type, signature algorithm, key, audience, nonce, and lifetime are acceptable;
- which external identity becomes which local account;
- which organisation, tenant, role, and permissions that account receives;
- when a new local session is created, rotated, refreshed, revoked, or recovered;
- whether logout, password reset, account disablement, and role changes alter existing sessions.
That sequence—not the login form—is the identity boundary. An identity provider can authenticate a person correctly while the customer application binds that identity to the wrong tenant, accepts a token intended for another client, preserves a pre-authentication session, or converts an ordinary claim into administrative authority.
The external pentester’s task is therefore not to attack the provider. It is to reconstruct the customer-controlled identity contract, then use approved test identities to verify the decisions that create local authority.
Authentication is not the same decision as authorization
Authentication answers a narrow question: which identity did a trusted authenticator establish? The business application has a different problem: what may that identity do here, in this tenant, with this object, at this point in the workflow?
OpenID Connect makes the distinction visible. An ID Token carries claims about an authentication
event and an end user. The relying party still has to validate the token and decide how its claims
map into local state. In particular, the OpenID Connect Core
specification defines iss, sub, and
aud as separate identity coordinates. A subject value is locally unique within an issuer; the
same sub under a different issuer is not the same identity. The audience identifies the client
for which the token was issued. A valid signature without those policy checks is not sufficient.
The JWT security best-practice document makes the application responsibility explicit: keys must belong to the trusted issuer, the issuer-subject pair must be valid for the application, and an audience intended for the recipient must be present and checked where tokens can serve multiple applications. See RFC 8725.
This produces a useful model:
The provider establishes an external identity. The application decides whether that identity is acceptable, which local principal it becomes, and which authority that principal receives.
When those three steps are collapsed into “SSO works,” the highest-value customer-controlled decisions disappear from the test plan.
The visible flow hides seven decision points
The seven points require different evidence.
| Decision point | Evidence to preserve | Security question |
|---|---|---|
| Login start | Application route, parameters, cookies, response, timestamp | Did the application initiate one specific flow for this browser? |
| Authorization request | Issuer host, client ID, redirect URI, scopes, state, nonce, PKCE | Is the request bound to the correct provider, client, and return route? |
| Callback | Return path, response mode, code or assertion, correlation state | Can a response be substituted, replayed, or attached to another flow? |
| Token validation | Token type, header, claims, key source, validation result | Are signature, issuer, audience, nonce, time, and token purpose enforced? |
| Account binding | Issuer-subject pair and local account identifier | Can two external identities collide or link to the same local account? |
| Authority conversion | Tenant, organisation, role, group, scope, entitlement source | Which claim or local record grants authority, and which one wins? |
| Local session and actions | Cookie lifecycle, account context, API calls, object effects | Does authority stay correct across login, refresh, change, and logout? |
Map the identity contract before testing it
The first pass should be observational. Start from the approved application entry point and record the redirect chain without attempting to enumerate provider tenants or probe real user accounts. Public metadata, customer configuration, browser requests, response headers, and the supplied test accounts are usually enough to establish the contract.
For each application, record:
- Entry point: the customer URL that starts login, including regional, partner, admin, mobile, and recovery variants.
- Protocol role: relying party or client, authorization server or identity provider, resource server, and any broker between them.
- Issuer and endpoints: exact issuer identifier, authorization and token endpoints, key source, callback routes, logout routes, and recovery routes.
- Client context: client ID, redirect URI, response type, response mode, scopes, and whether
PKCE,
state, andnonceappear. - Identity key: the fields used to bind the provider identity to a local account. Preferably this is the stable issuer-subject pair—not an editable email address or display name.
- Authority source: local database, provider group, application role, tenant membership, invitation, support override, or a combination.
- Session model: pre-login cookie, post-login cookie, refresh behavior, idle and absolute lifetime, concurrent sessions, logout, revocation, and device or tenant switching.
- Lifecycle edges: first login, invitation acceptance, account linking, email change, role change, tenant removal, password reset, MFA recovery, disablement, and deletion.
This inventory turns “uses SSO” into a falsifiable system model. Unknown fields stay marked unknown; they are not silently filled with provider defaults.
Protocol correctness is necessary, but policy creates the boundary
RFC 9700, the OAuth 2.0 Security Best Current Practice, recommends exact matching of registered redirect URIs, authorization code flows rather than exposing access tokens in browser URLs, and protections such as PKCE against authorization code injection. Those controls matter, but a protocol-compliant exchange can still lead to an unsafe local decision.
Consider four examples:
A trusted issuer, wrong audience. The signature is genuine and the token is current, but it was created for another client in the same identity estate. If the application verifies only the signature, it may accept authority never issued to it.
A correct user, wrong tenant. The issuer and subject are valid, but an organisation identifier is taken from a browser parameter after login rather than from verified membership. Authentication succeeds; tenant authorization fails.
A correct claim, wrong meaning. A provider group called billing-admin may be informational in
one application and privileged in another. The danger is not the claim’s authenticity. It is an
undocumented conversion from a broad directory group into a local administrative role.
A correct login, stale local session. The account is disabled or removed from a tenant at the provider, but an application session continues with cached authority. The authentication event was correct when it occurred; the lifecycle contract failed afterward.
The test plan should therefore distinguish two layers:
- protocol acceptance: can this response, token, or assertion be accepted by this client?
- business authority: after acceptance, which local account, tenant, role, objects, and effects become reachable?
Testing only the first layer produces a token checklist. Testing both layers produces an identity assessment.
The session is where external identity becomes local persistence
Federated login does not remove application session security. It moves the authentication event to another system, then asks the customer application to create and maintain local state.
Capture the unauthenticated cookie before login and compare it with the authenticated cookie after the callback. A privileged transition should not simply bless attacker-known pre-authentication state. OWASP’s session fixation testing guidance frames the core question: does the application issue a fresh session after successful authentication?
Rotation at login is only the first control. The same analysis belongs at every authority change:
| Transition | Expected local behavior |
|---|---|
| Anonymous → authenticated | Replace or safely rotate the session; bind it to the authenticated principal |
| User → administrator | Re-evaluate authority and rotate sensitive session state where appropriate |
| Tenant A → tenant B | Change tenant context explicitly; prevent object and cache bleed |
| Refresh | Preserve correct issuer, client, subject, tenant, and scope constraints |
| Password or MFA recovery | Invalidate or deliberately govern older sessions and recovery artifacts |
| Role or group removal | Remove effective authority within a defined, testable interval |
| Account disablement | Deny new sessions and revoke or expire existing sessions according to policy |
| Logout | Terminate the local session; distinguish local logout from provider SSO logout |
Cookie flags are useful evidence, not a complete conclusion. Secure, HttpOnly, SameSite,
Domain, Path, and lifetime settings describe how the browser handles an artifact. They do not
prove that the server rotates it, revokes it, binds it to the correct tenant, or stops accepting it
after the account changes.
Build a role and tenant matrix from controlled identities
Identity testing becomes defensible when every result has a comparison. Ask the customer for the smallest synthetic identity set that represents the important boundaries: unauthenticated, ordinary user, a second user in the same tenant, a user in another tenant, and one approved privileged role. Use customer-owned data and reversible actions.
The OWASP role-definition testing guidance starts from identifying and documenting the application’s roles. For a real assessment, extend that role list into a matrix of identity, tenant, object ownership, workflow state, and expected effect.
| Test identity | Tenant context | Object relation | Function | Expected result |
|---|---|---|---|---|
| Anonymous | None | None | View account dashboard | Deny and start login |
| User A | Meridian | Owner | Read own invoice | Allow |
| User B | Meridian | Same tenant | Read User A invoice | Deny unless explicitly shared |
| User C | Northwind | Other tenant | Read User A invoice | Deny |
| Billing admin | Meridian | Tenant managed | Approve invoice | Allow with recorded audit event |
| User A | Meridian | Owner | Assign admin role | Deny |
The most important column is the expected result. Without it, an HTTP 200 is merely an
observation. With it, the same response can prove either intended access or an authorization
failure. Record the downstream effect as well: data returned, record changed, message queued,
privilege granted, or nothing happened.
Negative controls make the finding believable
An identity result needs more than one successful request. A strong proof contains a valid control, an invalid comparison, and an observable effect.
Useful negative controls include:
- the same object with a different approved user;
- the same role in a different approved tenant;
- the same session after logout, role removal, or account disablement;
- the same callback with missing or mismatched flow correlation in a controlled test;
- the same signed token with the wrong intended audience in a customer test environment;
- the same function reached through UI and API routes;
- the same business action in an invalid workflow state.
Do not turn this matrix into indiscriminate token mutation. The purpose is to isolate the customer’s validation and authorization decisions with the minimum requests necessary, not to flood an identity provider with malformed traffic.
Keep the provider outside the line of fire
The identity provider may be architecturally important and contractually out of scope. That is normal. The assessment can still evaluate the customer-controlled relying party, client registration, callback handler, account-linking logic, local role conversion, API authorization, and session lifecycle.
Before active testing, make the boundary explicit:
- approved customer applications, callback routes, tenants, accounts, roles, and source addresses;
- whether the customer can provide a test identity tenant or isolated federation configuration;
- permitted login volume and MFA behavior;
- prohibited actions such as password spraying, real-user discovery, unsolicited MFA prompts, provider-tenant enumeration, or testing provider infrastructure;
- test objects and reversible effects;
- contacts and stop conditions for lockout, cross-tenant access, production data, or unexpected provider behavior.
A provider hostname in a redirect is evidence of a trust relationship, not permission to test the provider. If a hypothesis can only be proved by acting against the provider or real users, stop and request a scope decision or a customer-controlled test environment.
A fictional identity-boundary review
Assume the previous article identified partners.meridian.example as a current, approved partner
portal. The public route redirects to a corporate identity service, then returns to
/auth/callback and creates a local session.
- The analyst records the initial application cookie, redirect chain, exact issuer, client ID,
redirect URI, scopes,
state,nonce, and PKCE parameters. No provider endpoints beyond the normal customer login flow are probed. - Customer documentation confirms that the portal trusts one issuer and that partner membership should be stored locally. Two synthetic partner tenants and one billing-admin account are supplied.
- The valid flow proves that the issuer, callback, token, local account, tenant, and session can produce the expected User A dashboard. This is the positive control.
- Comparing the pre-login and post-login cookies shows rotation. Replaying the pre-login cookie after authentication remains anonymous. Session fixation is not supported.
- The application binds the external identity by issuer and subject, not by editable email. A second identity with the same synthetic email under the approved alternate test issuer does not collide with the first local account.
- The UI takes a
workspaceparameter, but the API derives effective tenant membership from the local session. Changing the browser parameter changes presentation only; cross-tenant objects remain denied. - One problem remains: the billing-admin role is copied into the session at login and is not re-evaluated after customer administrators remove the role. The old session can approve a synthetic invoice until its eight-hour expiry. A new session is correctly denied.
- The analyst records the positive admin control, the removed-role negative expectation, the old and new session comparison, the synthetic approval event, timestamps, and cleanup. Testing stops after one reversible object demonstrates the stale-authority window.
The finding is not “the provider issued a bad token.” The provider authenticated and described the test identity correctly. The customer application retained local authority after the source of that authority changed. The fix therefore belongs in session invalidation, entitlement refresh, and revocation design—not in the provider’s login screen.
Evidence matrix
| Observation or test | What it supports | What it cannot prove | Required next step |
|---|---|---|---|
| Public route redirects to an identity provider | An identity relationship exists in this browser flow | Provider ownership, tenant scope, or customer authorization | Record exact issuer, client, callback, and customer confirmation |
| OIDC metadata exposes endpoints and keys | Published protocol configuration for an issuer | That the application trusts or validates every field | Compare metadata with client behavior and configuration |
| Token signature validates | Token integrity under the selected key and algorithm | Trusted issuer, intended audience, valid subject, or role | Verify the complete application acceptance policy |
| ID Token contains email, groups, tenant, and roles | The issuer asserted those claims | Which claims create local identity or authority | Trace account binding and role conversion |
| Callback succeeds with a normal flow | One positive authentication path works | Resistance to substitution, replay, or correlation failure | Run bounded negative controls |
| Cookie flags are present | Browser handling restrictions exist | Rotation, server revocation, tenant binding, or logout | Compare session behavior across lifecycle transitions |
| Different role sees different navigation | The UI presents role-specific content | Server-side function or object authorization | Compare direct approved API requests and effects |
| Cross-tenant request returns a generic denial | One tested path enforced a tenant boundary | All object classes, alternate routes, or workflow states | Expand by risk and object class, not by blind enumeration |
| Removed role remains active in old session | Local authority can outlive its source for the measured time | Universal account takeover or provider failure | Bound duration, functions, revocation behavior, and impact |
| Logout removes the browser cookie | Client-side session artifact was cleared | Server-side invalidation or provider-wide logout | Reuse the old artifact safely and distinguish logout domains |
What defenders should receive
The deliverable should let identity, application, and platform teams see the same boundary.
Identity contract. Issuer, client, callback, key source, subject key, accepted token types, audience, correlation controls, and lifecycle assumptions.
Authority conversion map. External claims and local records that determine account, tenant, role, scope, and exceptional access. Conflicts and precedence rules should be explicit.
Session lifecycle. Creation, rotation, refresh, expiry, logout, revocation, role change, tenant removal, disablement, and recovery behavior, with measured windows rather than vague labels.
Permission matrix. Synthetic identities, roles, tenants, objects, workflow states, expected results, observed results, and evidence references.
Rejected hypotheses. Controls that worked should remain in the record: audience mismatch was rejected, pre-login state was rotated, cross-tenant reads failed, account identities did not collide. They define the tested boundary and prevent future teams from repeating the same work.
Actionable finding. The smallest failing policy, its application owner, reproducible evidence, bounded effect, cleanup, and a retest that includes both positive and negative controls.
The series ends where active testing can finally begin
This series started with a simple claim: the external perimeter is a graph, and a port list is only one view. Each article then removed one dangerous shortcut.
- A company name became an entity graph, not an automatic target list.
- A domain relationship became attributed evidence, not assumed ownership or scope.
- A third-party platform became a customer-controlled trust boundary, not permission to test the vendor.
- A passive service observation became a current application model, not a vulnerability claim.
- A public login page became an identity, tenant, role, and session contract, not proof that authorization was understood.
Only now is the test team ready to move from intelligence into application hypotheses. It knows which organisation owns the surface, which names and services are current, which suppliers carry authority, which application workflows matter, which identities and tenants are approved, and what evidence will distinguish intended access from a security failure.
That is the real value of quieter external pentesting. Passive intelligence does not replace active testing. It ensures that each active request reaches a boundary the customer actually owns, asks a question the application can answer, and produces evidence a defender can use.
How current is this note?
The latest source-review, content-update, or publication date is shown.
Primary public records were checked. Environment-specific behavior remains outside the claim unless separately reproduced.
