Sessions, Cookies, Tokens, and API AccessIntroductionModern web applications rarely rely on a single authentication mechanism. A browser application may authenticate a person with a password or an external identity provider, maintain a session with a cookie, call a separate API using an access token, and invoke background services using machine credentials. Each mechanism solves a different problem. Security failures occur when developers treat them as interchangeable or use a credential in a context for which it was not designed. This chapter examines browser sessions, cookies, CSRF protection, CORS, token storage, refresh and revocation, API keys, scopes, service accounts, machine identities, and authorization patterns for REST, GraphQL, and real-time systems. The central design principle is that authentication establishes who or what is making a request, whereas authorization determines what that subject is permitted to do. Learning ObjectivesBy the end of this chapter, students should be able to: - Explain how sessions, cookies, access tokens, refresh tokens, and API keys differ.
- Design secure browser authentication using cookie attributes and server-side controls.
- Analyze CSRF and CORS threats without confusing them with one another.
- Select suitable storage and rotation strategies for tokens.
- Apply scopes, roles, attributes, and resource ownership to API authorization.
- Compare REST, GraphQL, and real-time authorization requirements.
- Design credentials for service accounts and machine-to-machine communication.
- Evaluate authentication architectures against security, usability, operational, and regulatory requirements.
1. The Authentication State ModelAn authenticated interaction involves four related elements: - Principal: a human user, service, device, or workload.
- Credential: evidence presented by the principal, such as a password-derived proof, cookie, token, certificate, or API key.
- Authentication decision: the system’s determination that the credential is valid.
- Authorization decision: the system’s determination that the principal may perform a requested action on a particular resource.
A useful model is: Request → Credential extraction → Authentication → Authorization → Resource action
↓ ↓
Principal/context Policy decisionAuthentication context should include more than an identity identifier. It may include the issuer of a token, authentication strength, tenant, device posture, token age, and relevant security events. Authorization can then apply policies such as “a manager may approve expenses only within the manager’s department” rather than merely “the user has role manager.” Sessions and tokensA session is server-maintained state associated with a client after authentication. The browser commonly receives an opaque session identifier in a cookie. On each request, the server looks up the session record and applies its current status and permissions. A token is a credential containing, or referring to, authorization information. A bearer token grants access to whoever possesses it, unless additional proof-of-possession controls exist. A JSON Web Token (JWT) is a standardized token representation that can carry claims and be digitally signed, but JWT is a format, not a complete security architecture. | Mechanism | Typical holder | Server state | Main strength | Main risk |
|---|
| Opaque session ID | Browser cookie | Usually required | Easy revocation and policy change | Session theft or fixation | | Access token | Browser, mobile app, or service | Optional | Suitable for APIs and delegation | Leakage and overly broad authority | | Refresh token | Client application | Often required | Reduces repeated login | Long-lived credential theft | | API key | Application or integration | Usually required | Simple service identification | Poor user-level accountability | | Client certificate/private key | Workload or device | Registry required | Strong machine identity | Key lifecycle complexity |
2. Secure Browser Sessions and CookiesA cookie is a browser-managed name–value pair associated with a domain and path. Cookies are automatically attached to matching requests, which makes them convenient for sessions but creates cross-site request risks. Session lifecycleA robust session lifecycle includes: - Generate a high-entropy, unpredictable session identifier with a secure random generator.
- Replace any pre-authentication session identifier after successful login. This prevents session fixation, in which an attacker causes a victim to use a known identifier.
- Store only a reference in the cookie; keep sensitive state server-side where practical.
- Set an idle timeout and, where appropriate, an absolute lifetime.
- Rotate the identifier after privilege changes, password changes, and other sensitive events.
- Invalidate the session on logout, account suspension, credential compromise, or administrative revocation.
- Remove or expire the browser cookie as part of logout, while recognizing that server-side invalidation is the decisive control.
Session identifiers should not contain passwords, password hashes, or unnecessary personal information. A database or distributed session store should support lookup, expiration, revocation, and—when required—concurrent-session management. Cookie security attributesA session cookie should normally use the following attributes: - Secure: transmit the cookie only over HTTPS. This does not itself encrypt an HTTP response; the application must use HTTPS consistently, preferably with HSTS.
- HttpOnly: prevent ordinary JavaScript from reading the cookie. This reduces the usefulness of many XSS payloads for direct cookie theft, but does not prevent XSS from making requests as the victim.
- SameSite: restrict cross-site sending.
Strict offers strong protection but may affect some navigation flows. Lax is a common practical default. None permits cross-site use and requires Secure; it should be used only when cross-site behavior is necessary. - Domain and Path: narrow where the cookie is sent. Omitting
Domain creates a host-only cookie, often preferable to sharing it across subdomains. - Max-Age or Expires: define persistence. Session cookies disappear according to browser session behavior, but explicit expiration is usually clearer.
Cookie prefixes such as __Host- can impose useful browser-enforced constraints: a secure cookie, no Domain attribute, and a path of /. They are valuable for high-integrity session cookies where supported. Threats against browser sessionsSession hijacking occurs when an attacker obtains a valid session identifier. Common causes include malware, insecure transport, logs containing credentials, browser compromise, or XSS-assisted actions. Use HTTPS, avoid logging secrets, protect endpoints against XSS, and rotate or revoke sessions after suspicious activity. Session fixation occurs when the server accepts an attacker-selected identifier and retains it after login. Regenerating the identifier at authentication and privilege elevation prevents this class of attack. Session replay occurs when a stolen credential is reused. Shorter lifetimes, device or risk signals, token binding alternatives, and server-side revocation reduce the window, although no control should be described as an absolute cure. 3. CSRF and CORS: Related but DifferentCross-site request forgeryCSRF exploits the browser’s automatic inclusion of credentials. Suppose a user is logged in to bank.example; an attacker’s page submits a transfer form to that site. If the bank accepts the cookie automatically and does not verify the request’s intent, the action may execute. Important defenses include: SameSite cookies, chosen consistently with the application’s navigation requirements.- Anti-CSRF tokens: a server-generated unpredictable value is placed in a form or request header and checked against the user’s session.
- Origin or Referer validation for state-changing requests, with careful handling of privacy-related header omission.
- Avoiding state changes through
GET; use methods and content types that reflect the operation. - Reauthentication or step-up authentication for high-impact actions.
A CSRF token is not a substitute for authentication. It proves that the request came through an expected application flow; it does not identify the user independently. Cross-origin resource sharingCORS is a browser policy controlling whether JavaScript from one origin may read responses from another origin. An origin is the combination of scheme, host, and port. CORS does not prevent a server from receiving every request, and it is not a general server-to-server access-control mechanism. For a permitted cross-origin request, the server may return Access-Control-Allow-Origin with an explicit trusted origin. If cookies or other credentials are used, the server must also return Access-Control-Allow-Credentials: true, and it must not use the wildcard * as the allowed origin for credentialed access. The server should vary cached responses by the Origin request header when dynamically reflecting approved origins. A browser may send a preflight OPTIONS request before a non-simple request. The server’s response can specify permitted methods and headers. CORS configuration should use an allowlist, not arbitrary reflection of the request origin. CSRF asks, “Can an unwanted request be induced?” CORS asks, “May browser JavaScript read a cross-origin response?” A permissive CORS policy can expose data, but a restrictive CORS policy alone does not stop cookie-based CSRF. 4. Access Tokens and Refresh TokensAn access token is usually short-lived and presented to an API, commonly through the Authorization: Bearer <token> header. A refresh token is longer-lived and exchanged with an authorization server for a new access token. Refresh tokens should be sent only to the token endpoint, not to ordinary resource APIs. Opaque and self-contained tokensAn opaque token has no useful meaning to the client or resource server. The API validates it through an introspection endpoint or shared authorization service. Revocation and policy changes are straightforward, but introspection adds availability and latency concerns. A self-contained signed token, such as a JWT, can be verified locally. Typical claims include: iss: issuer;sub: subject;aud: intended audience;exp: expiration time;nbf: not-before time;iat: issue time;jti: token identifier;scope or equivalent authorization claims.
The resource server must validate the signature using trusted keys, issuer, audience, time constraints, and required claims. It must not accept an algorithm merely because the token requests it, nor should it treat decoded claims as trustworthy before signature verification. A valid signature means the trusted issuer signed the token; it does not prove that the token is appropriate for the receiving API. Token storageFor a browser application, storing long-lived tokens in localStorage or sessionStorage exposes them to JavaScript running in the origin. An XSS vulnerability can therefore read and exfiltrate them. A common safer design is an HttpOnly, Secure, appropriately SameSite refresh cookie combined with short-lived access tokens held in memory. This arrangement still requires XSS defenses and CSRF protection for the refresh endpoint. For native mobile applications, platform-provided secure storage and authorization-code flows with Proof Key for Code Exchange (PKCE) are preferable to embedding client secrets in the application. A public client cannot keep a secret merely because the source code is obfuscated. Refresh rotation and reuse detectionRefresh-token rotation issues a new refresh token whenever one is used and invalidates the previous token. If an old token is presented again, the server can infer possible theft and revoke the associated token family or session. Rotation is especially useful when immediate, universal revocation is operationally difficult. A practical design records a token-family identifier, token hash, issue time, expiry, client, and revocation status. Store hashes rather than plaintext refresh tokens where feasible. Access-token revocation is harder when tokens are self-contained; short lifetimes, introspection, deny lists for exceptional cases, and event-driven session invalidation are complementary strategies. 5. API Keys, Scopes, and Authorization PoliciesAn API key identifies an application, integration, or project. It is not normally proof of a human user and should not be used as a universal replacement for user authentication. Keys should be scoped, rate-limited, monitored, rotatable, and separated by environment. They must not be embedded in public browser code or committed to source control. Scopes express delegated capabilities, such as orders:read or orders:write. The principle of least privilege requires issuing only the scopes needed for a task. However, a scope is generally a coarse capability. The API must still check resource ownership, tenant boundaries, object state, and business rules. Common authorization models include: - RBAC: permissions are assigned to roles, and users receive roles. It is understandable but can produce role explosion.
- ABAC: policies evaluate attributes of the subject, resource, action, and environment, such as department, classification, time, or device trust.
- Relationship-based authorization: permissions derive from relationships such as “user is an editor of document 17” or “employee belongs to project team.”
- Policy-based authorization: a policy engine evaluates structured rules, while the application supplies trusted context and enforces the decision.
A secure authorization decision can be represented conceptually as: Permit(subject, action, resource, context) The decision should be made on the server for every relevant operation. Hiding a button in a user interface is a usability feature, not an authorization control. 6. Machine Identities and Service AccountsA service account is a non-human identity used by an application or workload. A machine identity is the broader identity of a workload, device, or automated actor. Each workload should have a distinct identity rather than sharing one global credential. Distinct identities enable least privilege, attribution, rotation, and rapid containment. Credential options include: - short-lived access tokens obtained through a workload identity system;
- client certificates and mutual TLS (mTLS);
- signed assertions using a protected private key;
- cloud-provider instance or workload identity mechanisms;
- narrowly scoped API keys when stronger mechanisms are unavailable.
A client secret in a server-side application is confidential only if the server protects it. It is not confidential in a browser, mobile binary, or public repository. Secret managers, key rotation, access auditing, and separation of deployment environments are operational necessities. Machine authorization should distinguish identity from permission. A payment-processing service may be authenticated as payment-worker, yet be authorized only to read queued payment jobs and submit results—not to administer users or issue arbitrary refunds. 7. API-Specific AuthorizationRESTREST APIs should authenticate requests consistently and authorize each resource operation. Method names are not sufficient: GET /accounts/17 still requires an object-level authorization check. Prevent insecure direct object references by verifying that the authenticated subject may access the requested identifier. Use explicit status codes without revealing unnecessary information; for example, some systems deliberately return the same response for nonexistent and unauthorized resources to reduce enumeration. State-changing operations should support idempotency where retries could duplicate effects, especially for payments or provisioning. Authorization should be evaluated again after asynchronous jobs are created, because a user’s permissions may change before job execution. GraphQLGraphQL often exposes a single endpoint, so network-path authorization is insufficient. Authorization should be applied at resolver or service boundaries, and nested objects must be checked individually. Query depth, field complexity, batching, and aliasing require limits to reduce denial-of-service and data-exposure risks. Avoid returning fields merely because a parent object was authorized; a user allowed to view a project may not be allowed to view its payroll data. Introspection may be restricted in production when schema discovery creates unnecessary exposure, but disabling introspection is not a substitute for authorization. Real-time applicationsWebSocket and similar connections authenticate during the handshake, but authorization must continue throughout the connection’s lifetime. A connection established before a role change may need revalidation. Each subscription, channel, room, and message action requires authorization. Do not place bearer tokens in URLs, because URLs can enter logs, browser history, and monitoring systems. Prefer secure headers or carefully designed handshake mechanisms. Server-sent events and long polling have similar concerns: authenticate the stream, authorize each requested topic, and close or reauthorize it when the session expires or privileges change. 8. Illustrative Case: Campus Collaboration PlatformBackgroundA fictional university platform allows students and staff to collaborate in courses. It has a browser front end, a REST API for assignments, a GraphQL API for dashboards, and WebSocket notifications. A separate grading service processes submissions. ProblemThe initial implementation stores a long-lived JWT in localStorage, accepts a wildcard CORS policy, uses one API key for all grading environments, and checks only whether a user is logged in—not whether the user belongs to the course. A malicious page can induce requests, and a leaked grading key can access production data. AnalysisThe design combines several failures. Browser-readable long-lived credentials increase the impact of XSS. Wildcard CORS is incompatible with safe credentialed cross-origin reading and may expose poorly designed endpoints. A shared key prevents attribution and makes rotation disruptive. Authentication without object-level authorization permits cross-course access. Approach and solutionThe platform adopts an authorization server and a backend-for-frontend pattern. The browser receives a Secure, HttpOnly, host-only session cookie with an appropriate SameSite setting. State-changing requests use a CSRF token and Origin validation. The backend calls APIs with short-lived access tokens, while refresh state is rotated and stored server-side or in protected cookies. REST endpoints check both scopes and course membership. GraphQL resolvers apply field-level policies. WebSocket subscriptions authorize course channels and recheck authorization when subscriptions are created. The grading service receives a separate workload identity with only submission-read and result-write permissions. Development, staging, and production identities are separate; secrets are stored in a secret manager and rotated. OutcomeThe revised architecture reduces credential exposure, supports targeted revocation, improves auditability, and prevents a valid student identity from crossing course boundaries. It also makes incident response practical: a single workload or session can be revoked without disabling every integration. Learning points- A token format cannot replace a complete threat model.
- CORS and CSRF address different browser behaviors.
- Authorization must be applied at the resource and field level.
- Separate machine identities improve least privilege and accountability.
- Security controls must include lifecycle operations, not only login.
9. Governance, Privacy, and Operational PracticeAuthentication systems process sensitive personal and behavioral data. Collect only the information needed for security and service delivery. Define retention periods for sessions, audit records, device identifiers, and token metadata. Protect logs because URLs, headers, and exception traces can accidentally contain credentials or personal data. Audit records should answer who or what acted, what action occurred, which resource was affected, when it occurred, the authentication method, and the outcome. Access to audit data must itself be controlled. Compliance obligations vary by jurisdiction and sector, but principles such as data minimization, access control, breach response, and demonstrable accountability are broadly relevant. Security testing should include session fixation, CSRF, CORS misconfiguration, token replay, refresh-token reuse, object-level authorization, GraphQL over-fetching, WebSocket subscription abuse, secret leakage, and privilege changes during long-lived connections. Automated tests should assert denial as well as success. Contemporary systems increasingly use passkeys and phishing-resistant authentication for the initial user login, while still using sessions or tokens for application access. Zero-trust architectures emphasize continuously evaluated identity, device and workload context, and least privilege rather than implicit trust based on network location. AI-assisted coding can accelerate implementation, but generated authentication code requires expert review, threat modeling, dependency analysis, and tests; plausible code can contain subtle authorization flaws. Best-Practice Checklist- Use HTTPS everywhere and protect cookies with Secure, HttpOnly, and suitable SameSite settings.
- Regenerate sessions after login and privilege changes.
- Keep access tokens short-lived and narrowly scoped.
- Protect refresh tokens, rotate them, and detect reuse.
- Never place secrets in browser code, URLs, logs, or repositories.
- Treat CORS as a browser read policy, not as authentication or CSRF protection.
- Authorize every sensitive resource, field, channel, and background job.
- Give each service its own machine identity and minimum permissions.
- Validate token issuer, audience, signature, time claims, and required claims.
- Plan revocation, rotation, monitoring, incident response, and recovery before deployment.
Chapter SummarySessions place authentication state under server control and are often appropriate for browser applications. Cookies make sessions convenient, but Secure, HttpOnly, SameSite, scoped domain/path, expiration, rotation, and server-side invalidation are essential controls. CSRF exploits automatic credential inclusion, whereas CORS governs whether browser JavaScript may read cross-origin responses; neither should be confused with the other. Access tokens should be short-lived, audience-restricted, and minimally scoped. Refresh tokens require stronger protection, rotation, and reuse detection. JWTs provide a signed representation, not automatic authorization correctness. API keys are useful integration credentials but are weak substitutes for user identity and must be scoped and rotated. Authorization should combine scopes with resource-level, relationship, and business-rule checks. REST, GraphQL, and real-time systems each require authorization at their own execution boundaries. Service accounts and machine identities should be distinct, least-privileged, auditable, and supported by secure lifecycle management. A professional design treats authentication as a complete lifecycle involving issuance, use, monitoring, revocation, privacy, and incident response. Key TermsPrincipal: Human, service, device, or workload making a request. Credential: Evidence used to authenticate a principal. Session: Server-maintained authentication state associated with a client. Session fixation: Attack in which a known session identifier is retained after login. Cookie: Browser-managed data automatically sent with matching requests. CSRF: Attack that induces a browser to perform an unwanted authenticated action. CORS: Browser mechanism controlling permitted cross-origin response access. Access token: Short-lived credential presented to a resource server. Refresh token: Credential exchanged for new access tokens. Bearer token: Token usable by whoever possesses it. JWT: Signed or encrypted token representation containing claims. API key: Credential identifying an application or integration. Scope: Delegated capability assigned to a token or client. RBAC: Authorization model based on roles and permissions. ABAC: Authorization model based on subject, resource, action, and context attributes. Service account: Non-human identity used by an application or process. Machine identity: Identity representing a workload, device, or automated actor. mTLS: Mutual TLS, in which both communicating parties authenticate with certificates. Object-level authorization: Check that a subject may access a particular resource instance. Token revocation: Making an otherwise valid credential unacceptable before normal expiry. Review Questions5 Short Answer Questions- What is the difference between authentication and authorization?
- Why should a session identifier be regenerated after login?
- What do the Secure and HttpOnly cookie attributes do?
- Why is CORS not a substitute for CSRF protection?
- What is the purpose of refresh-token rotation?
5 Long Answer Questions- Explain how to design a secure browser session lifecycle from login through logout and revocation.
- Compare opaque access tokens with self-contained JWTs, including operational advantages and limitations.
- Explain RBAC, ABAC, and relationship-based authorization, and identify circumstances in which each is useful.
- Design an authorization approach for a GraphQL API that prevents unauthorized nested-field access.
- Discuss the security and governance requirements for service accounts and machine identities.
3 Analytical / Application Questions- An application uses cookies for authentication, allows
Access-Control-Allow-Origin: *, and performs money transfers through GET requests. Identify the major risks and propose a corrected design. - A WebSocket connection remains open for eight hours while a user’s role is downgraded after one hour. Explain what authorization controls should occur at connection, subscription, message, and role-change stages.
- A company discovers that the same API key is embedded in its mobile app, staging server, and production server. Analyze the consequences and develop a migration plan using appropriate identities, scopes, rotation, and monitoring.
Multiple Choice Questions with AnswersQuestion 1Which cookie attribute prevents ordinary JavaScript from reading a session cookie? A. Secure B. HttpOnly C. SameSite D. Max-Age Correct Answer: B. HttpOnly Question 2What is the primary purpose of a CSRF token? A. To encrypt a password B. To identify an API server C. To demonstrate that a state-changing request came through an expected application flow D. To permit all cross-origin responses Correct Answer: C. To demonstrate that a state-changing request came through an expected application flow Question 3Which statement about CORS is correct? A. It prevents a server from receiving every cross-origin request B. It replaces object-level authorization C. It controls whether browser JavaScript may read a cross-origin response D. It makes API keys unnecessary Correct Answer: C. It controls whether browser JavaScript may read a cross-origin response Question 4Which claim identifies the intended recipient API of a token? A. iss B. aud C. iat D. jti Correct Answer: B. aud Question 5Why is storing a long-lived access token in localStorage risky in a browser? A. The browser automatically deletes it after every request B. It cannot be used with HTTPS C. JavaScript running through an XSS vulnerability may read and exfiltrate it D. It prevents the server from validating signatures Correct Answer: C. JavaScript running through an XSS vulnerability may read and exfiltrate it Question 6What is the main security benefit of refresh-token rotation? A. It makes access tokens permanent B. It can reveal reuse of a previously used refresh token C. It removes the need for HTTPS D. It grants every client the same permissions Correct Answer: B. It can reveal reuse of a previously used refresh token Question 7Which authorization check is essential for GET /accounts/17? A. Only checking that the request uses HTTPS B. Only checking that the user is logged in C. Checking that the authenticated subject may access account 17 D. Checking whether the URL is shorter than 17 characters Correct Answer: C. Checking that the authenticated subject may access account 17 Question 8Which credential is generally most appropriate for a distinct server-side workload when short-lived workload tokens are available? A. A password shared by all services B. A browser localStorage token C. A dedicated workload identity with least-privilege permissions D. A token embedded in a public repository Correct Answer: C. A dedicated workload identity with least-privilege permissions Question 9Why must GraphQL authorization be applied to nested fields or resolvers? A. A single authorized parent object automatically authorizes every field B. Different nested fields may have different sensitivity and permissions C. GraphQL cannot use TLS D. Resolvers are used only for performance Correct Answer: B. Different nested fields may have different sensitivity and permissions Question 10Which action best prevents session fixation? A. Keeping the same session identifier after login B. Regenerating the session identifier after successful authentication C. Putting the session identifier in a URL D. Disabling server-side session expiration Correct Answer: B. Regenerating the session identifier after successful authentication
|