AJAX - AJAX Request Credentials and Cookie-Based Sessions
AJAX requests can communicate with a server without reloading the entire webpage. In many web applications, the server needs to know which user is making a request. This is commonly handled through cookies and session-based authentication. When an AJAX request includes the appropriate credentials, the browser can send cookies associated with the server, allowing the server to identify the user's session.
What Are Request Credentials?
Request credentials refer to authentication-related information that the browser may include when making a request. This can include cookies, TLS client certificates, and other browser-managed credentials. In traditional applications, cookies are often the most important type because they can contain a session identifier.
For example, after a user logs into a website, the server may create a session and send a cookie to the browser:
Set-Cookie: sessionId=ABC123
The browser stores this cookie according to its rules. When the browser later makes another request to the same website, it may automatically attach the cookie:
Cookie: sessionId=ABC123
The server can then use the session ID to determine which logged-in user is making the request.
Cookies in AJAX Requests
An AJAX request made using XMLHttpRequest can participate in cookie-based authentication. For same-origin requests, browsers generally handle relevant cookies automatically.
Example:
const xhr = new XMLHttpRequest();
xhr.open("GET", "/profile", true);
xhr.onload = function () {
if (xhr.status === 200) {
console.log(xhr.responseText);
}
};
xhr.send();
If the user has an active session for the website, the browser can send the appropriate session cookie with the request. The server can therefore return information associated with that user's session.
This makes AJAX useful for applications such as dashboards, shopping carts, account pages, and administrative systems where different users need to receive different information.
withCredentials in XMLHttpRequest
The withCredentials property becomes particularly important when an AJAX request is made across origins.
For example:
const xhr = new XMLHttpRequest();
xhr.open("GET", "https://api.example.com/profile", true);
xhr.withCredentials = true;
xhr.onload = function () {
if (xhr.status === 200) {
console.log(xhr.responseText);
}
};
xhr.send();
Setting:
xhr.withCredentials = true;
indicates that the browser is allowed to include credentials such as cookies in a cross-origin request, subject to the browser's cookie and security policies.
However, setting withCredentials alone does not make a cross-origin request work. The server must also provide the appropriate CORS response headers, and the cookies themselves must satisfy applicable cookie restrictions.
Same-Origin and Cross-Origin Requests
A same-origin request occurs when the webpage and requested resource share the same scheme, host, and port.
For example:
https://example.com/page
https://example.com/api/data
These have the same origin.
A cross-origin request occurs when one or more of these components differs.
For example:
https://example.com
https://api.example.com
These are different origins because their hosts differ.
Cross-origin requests are subject to additional browser security rules. When credentials such as cookies are involved, the server must explicitly permit credentialed cross-origin requests.
A server may respond with headers such as:
Access-Control-Allow-Origin: https://example.com
Access-Control-Allow-Credentials: true
The server cannot use a wildcard origin together with credentialed CORS in the usual browser CORS model:
Access-Control-Allow-Origin: *
when credentials are requested.
Cookie-Based Sessions
A session-based authentication system normally follows a sequence like this:
-
The user submits login credentials.
-
The server verifies the credentials.
-
The server creates a session.
-
The server sends a session cookie to the browser.
-
The browser stores the cookie.
-
Subsequent AJAX requests include the cookie when applicable.
-
The server reads the session identifier.
-
The server identifies the logged-in user.
-
The server returns the appropriate response.
For example, after authentication, the server might issue:
Set-Cookie: sessionId=XYZ789; Secure; HttpOnly
A later AJAX request might contain:
Cookie: sessionId=XYZ789
The application does not normally need to manually read the HttpOnly cookie using JavaScript.
Why HttpOnly Is Important
A cookie marked with the HttpOnly attribute cannot normally be accessed through JavaScript's document.cookie API.
For example:
Set-Cookie: sessionId=XYZ789; HttpOnly; Secure
This is useful for session cookies because application JavaScript does not need direct access to the session identifier.
It helps reduce the impact of certain cross-site scripting attacks, because injected JavaScript cannot simply read an HttpOnly session cookie. It does not, however, prevent an attacker from making requests using the victim's browser if other security protections are absent.
The Secure Attribute
The Secure attribute instructs the browser to send the cookie only over secure HTTPS connections.
Example:
Set-Cookie: sessionId=XYZ789; Secure
Using secure cookies is important for protecting authentication information from being transmitted over an unencrypted HTTP connection.
For production applications, authentication cookies should generally be protected with HTTPS and appropriate cookie attributes.
The SameSite Attribute
The SameSite attribute controls when cookies are sent in cross-site contexts.
Common values include:
SameSite=Strict
SameSite=Lax
SameSite=None
Strict provides stronger restrictions on cross-site cookie sending.
Lax permits cookies in some cross-site situations and is commonly used as a practical default.
None allows cross-site cookie use, but modern browsers generally require such cookies to also have:
Secure
For example:
Set-Cookie: sessionId=XYZ789; SameSite=None; Secure
This is particularly relevant when an AJAX application and authentication service operate across different sites.
Credentials and Security
Credentialed AJAX requests must be designed carefully because cookies automatically carry authentication information. An incorrectly configured application can unintentionally expose authenticated resources.
Important protections include:
-
Use HTTPS for authenticated communication.
-
Configure CORS with specific trusted origins.
-
Avoid unnecessarily allowing credentials for untrusted origins.
-
Use
HttpOnlyfor session cookies when JavaScript does not need access. -
Use
Securefor authentication cookies. -
Select an appropriate
SameSitepolicy. -
Protect state-changing operations against CSRF attacks.
-
Validate authentication and authorization on the server for every protected request.
Client-side code should never be treated as the authority for deciding whether a user is allowed to access a resource. The server must perform authentication and authorization checks.
AJAX Credentials and CSRF
Cookie-based authentication creates an important security consideration known as Cross-Site Request Forgery (CSRF).
Suppose a user is logged into:
https://bank.example
A malicious website could potentially cause the user's browser to make a request to the banking website. If the browser automatically includes the authentication cookie, the banking server may see the request as coming from the authenticated user.
For state-changing operations such as changing an email address or transferring money, applications should use appropriate CSRF defenses. These can include SameSite cookies, CSRF tokens, origin checks, and other server-side protections depending on the architecture.
Difference Between Cookies and Authorization Headers
Cookie-based authentication is not the only authentication approach for AJAX applications.
A request may instead use an authorization header:
Authorization: Bearer <token>
With cookie-based sessions, the browser can manage the session cookie automatically.
With token-based approaches, application code may explicitly attach an access token to requests.
The two approaches have different security and architectural considerations. Cookie-based authentication is particularly convenient for traditional browser applications, while bearer-token approaches are commonly used in certain APIs and distributed application architectures.
Practical Example
Consider an online shopping website. A user logs in and receives a session cookie:
Set-Cookie: sessionId=ABC123; HttpOnly; Secure; SameSite=Lax
The webpage then makes an AJAX request:
const xhr = new XMLHttpRequest();
xhr.open("GET", "/api/cart", true);
xhr.onload = function () {
if (xhr.status === 200) {
const cart = JSON.parse(xhr.responseText);
console.log(cart);
}
};
xhr.send();
The browser can send the session cookie with the request. The server receives the request, identifies session ABC123, determines which customer owns that session, retrieves that customer's shopping cart, and sends the cart information back.
The page can then update only the shopping-cart section instead of refreshing the entire webpage.
Conclusion
AJAX request credentials allow asynchronous requests to work with authentication mechanisms such as cookies and server-side sessions. Cookie-based sessions are especially useful because the browser can manage authentication cookies while AJAX requests communicate with protected server resources.
For same-origin requests, cookies are generally handled automatically according to browser rules. For cross-origin requests, credential handling requires additional configuration through withCredentials, CORS, and appropriate cookie attributes. Secure implementation also requires HTTPS, careful CORS configuration, suitable SameSite settings, HttpOnly and Secure cookies where appropriate, and protection against CSRF attacks.