So in postman, I am sending using this header
and this is working fine. (YW string is admin:admin encoded using base64).
I'm trying to do the same in javascript, but I keep on getting a 403.
headers.append('Content-Type', 'application/json');
if (window.location.host.indexOf('localhost') != -1) {
headers.append('Authorization', 'Basic YWRtaW46YWRtaW4=');
}
const response = await fetch(myUrl,
{
method: 'POST',
headers: headers,
body: payload
}
);
Any ideas on how it can be done? Thanks
Solved! Go to Solution.
Views
Replies
Total Likes
Hi @jayv25585659 ,
Here’s a quick way to make a POST request to your AEM endpoint using a pre-encoded Basic Auth token and a local CSRF bypass for testing.
const headers = new Headers({
'Content-Type': 'application/json',
'Authorization': 'Basic YWRtaW46YWRtaW4=', // pre-encoded token
'CSRF-Token': 'nocheck' // for local testing
});
const res = await fetch('http://localhost:4502/bin/your/servlet/endpoint', {
method: 'POST',
headers,
credentials: 'include',
body: JSON.stringify(payload)
});
Notes:
Make sure payload is JSON.stringified.
credentials: 'include' sends cookies/session.
For production, replace 'nocheck' with a real CSRF token.
Thanks,
Lavish Vasuja
Hi @jayv25585659, you can try configuring "Adobe Granite Cross-Origin Resource Sharing Policy" configuration to allow the domain from where JS calls occur.
Hi @jayv25585659,
Here’s what’s actually happening - Postman works because it’s not affected by browser security rules. But when you call your AEM servlet via JavaScript in a web page:
Basic Auth header is correct
Browser blocks the request -> 403 due to CORS / CSRF / Sling Referrer Filter
Add these headers:
const headers = new Headers();
headers.append("Content-Type", "application/json");
headers.append("Authorization", "Basic YWRtaW46YWRtaW4="); // admin:admin
headers.append("CSRF-Token", "nocheck"); // Important for POST in Author
Then:
const response = await fetch("http://localhost:4502/bin/acara/principals/accessrequest", {
method: "POST",
credentials: "include",
headers: headers,
body: JSON.stringify(payload)
});
For AEM Author only
You also need to whitelist your local site:
AEM -> Web Console ->
OSGi Config -> Adobe Granite Cross-Origin Resource Sharing Policy
Add:
Allowed Origins: http://localhost:3000 (or your front-end port)
Allowed Headers: Authorization, Content-Type, CSRF-Token
Supported Methods: POST, GET, OPTIONS
Adobe Granite Referrer Filter
-> Add localhost to allow list
Quick Test to Confirm Your Servlet Works in Browser
Open browser DevTools:
fetch("http://localhost:4502/bin/acara/principals/accessrequest", {
method: "POST",
headers: {
"Authorization": "Basic YWRtaW46YWRtaW4=",
"Content-Type": "application/json",
"CSRF-Token": "nocheck"
},
body: JSON.stringify({ test: true })
}).then(r => console.log(r.status, r.text()));
If this works -> CORS/Referrer are the missing pieces in your frontend app.
Hi @jayv25585659 ,
This is a classic browser vs Postman issue. Postman skips browser security (no preflight/CORS and no enforced CSRF), so a request that works there can get 403 from the browser. Two things to check/fix:
1) CORS / preflight
Open DevTools → Network and look for the OPTIONS request (preflight).
If OPTIONS returns 4xx or is missing Access-Control-Allow-* headers, configure AEM to allow the origin, Authorization, Content-Type, CSRF-Token and the POST method.
Browser requires server to reply with these headers for the real POST to be allowed.
2) AEM CSRF protection (very common cause)
AEM often requires a CSRF token on POSTs. Postman may work without it; the browser will not.
Fetch the token and send it in CSRF-Token header before your POST.
Minimal flow (works cross-origin if CORS is allowed):
// Step 1: Fetch CSRF token
const getCsrfToken = async () => {
const response = await fetch('http://localhost:4502/libs/granite/csrf/token.json', {
credentials: 'include',
});
if (!response.ok) {
throw new Error(`Failed to fetch CSRF token: ${response.statusText}`);
}
const data = await response.json();
return data.token;
};
// Step 2: Send POST request with Basic Auth and CSRF token
const sendAccessRequest = async (payload) => {
const token = await getCsrfToken();
const response = await fetch('http://localhost:4502/bin/acara/principals/accessrequest.json', {
method: 'POST',
mode: 'cors', // required for cross-origin requests
credentials: 'include', // include cookies/session
headers: {
'Content-Type': 'application/json',
'Authorization': 'Basic YWRtaW46YWRtaW4=',
'CSRF-Token': token,
},
body: JSON.stringify(payload),
});
if (!response.ok) {
throw new Error(`Request failed: ${response.status} ${response.statusText}`);
}
return response.json();
};
// Example usage
try {
const payload = { /* your request body */ };
const result = await sendAccessRequest(payload);
console.log('Access request successful:', result);
} catch (error) {
console.error('Error:', error);
}
Hope this helps.
Regards,
Manvi Sharma
Hi @jayv25585659 ,
Here’s a quick way to make a POST request to your AEM endpoint using a pre-encoded Basic Auth token and a local CSRF bypass for testing.
const headers = new Headers({
'Content-Type': 'application/json',
'Authorization': 'Basic YWRtaW46YWRtaW4=', // pre-encoded token
'CSRF-Token': 'nocheck' // for local testing
});
const res = await fetch('http://localhost:4502/bin/your/servlet/endpoint', {
method: 'POST',
headers,
credentials: 'include',
body: JSON.stringify(payload)
});
Notes:
Make sure payload is JSON.stringified.
credentials: 'include' sends cookies/session.
For production, replace 'nocheck' with a real CSRF token.
Thanks,
Lavish Vasuja