Javascript - fetch requests with Bearer tokens
Table of Contents
Obtaining the Token
- This example assumes you already have the
oauthToken
. - Getting the token involves a separate OAuth flow (like Authorization Code flow, Implicit flow, Client Credentials flow, etc.), which is usually handled before we make these API calls.
- The specific flow depends on the API provider.
How to use JavaScript’s fetch
API to make requests to a server that requires an OAuth 2.0 Bearer token for authorization?
The core idea is to add an Authorization
header to your fetch
request options.
Common OAuth 2.0 Method: Bearer Token
Most modern APIs using OAuth 2.0 expect the token to be sent in the Authorization
header using the Bearer
scheme.
Example GET Request using Promises
// --- Configuration ---
const apiUrl = 'YOUR_API_ENDPOINT';
const oauthToken = 'YOUR_OAUTH_TOKEN';
// --- Fetch Options ---
const requestOptions = {
method: 'GET', // Or 'POST', 'PUT', 'DELETE', etc.
headers: {
// Crucial header for OAuth 2.0 Bearer Token
'Authorization': `Bearer ${oauthToken}`,
// Optional, but common headers
'Accept': 'application/json', // Tell the server we want JSON back
// 'Content-Type': 'application/json' // Needed for POST/PUT requests with JSON body
},
// body: JSON.stringify(yourDataObject) // Needed for POST/PUT requests
};
fetch(apiUrl, requestOptions)
.then(response => {
// Check if the request was successful (status code 200-299)
if (!response.ok) {
// If not successful, throw an error to be caught by .catch()
// You might want more sophisticated error handling here
throw new Error(`HTTP error! Status: ${response.status}`);
}
// Parse the JSON response body
return response.json(); // returns another promise
})
.then(data => {
// Handle the successful response data
console.log('Success:', data);
// Do something with the data...
})
.catch(error => {
// Handle errors during the fetch or processing
console.error('Error fetching data:', error);
});
Example GET Request using async/await
async function fetchData() {
const apiUrl = 'YOUR_API_ENDPOINT';
const oauthToken = 'YOUR_OAUTH_TOKEN';
const requestOptions = {
method: 'GET',
headers: {
'Authorization': `Bearer ${oauthToken}`,
'Accept': 'application/json',
}
};
try {
const response = await fetch(apiUrl, requestOptions);
if (!response.ok) {
// Get more error details if possible
let errorData = null;
try {
// Try to parse error response body if server provides one
errorData = await response.json();
} catch (parseError) {
// Ignore if response body isn't JSON
}
console.error('Server returned an error:', response.status, response.statusText, errorData);
throw new Error(`HTTP error! Status: ${response.status}`);
}
const data = await response.json();
console.log('Success (async/await):', data);
// Process the data...
return data; // Optionally return the data
} catch (error) {
console.error('Error fetching data (async/await):', error);
// Handle the error appropriately (e.g., show a message to the user)
}
}
// Call the async function
fetchData();
Example POST Request with JSON Body using async/await
async function postData(dataToSend) {
const apiUrl = 'YOUR_API_ENDPOINT_FOR_POST'; // Endpoint that accepts POST
const oauthToken = 'YOUR_OAUTH_TOKEN';
const requestOptions = {
method: 'POST',
headers: {
'Authorization': `Bearer ${oauthToken}`,
'Accept': 'application/json',
// Crucial for sending JSON data
'Content-Type': 'application/json'
},
// Convert the JavaScript object to a JSON string
body: JSON.stringify(dataToSend)
};
try {
const response = await fetch(apiUrl, requestOptions);
if (!response.ok) {
let errorData = null;
try {
errorData = await response.json();
} catch (e) { /* ignore */ }
console.error('POST Error:', response.status, response.statusText, errorData);
throw new Error(`HTTP error! Status: ${response.status}`);
}
// Often POST requests return the created/updated resource or just a success status
// Decide if you need to parse the body based on the API documentation
// If the API returns an empty body on success (e.g., status 201 or 204),
// calling response.json() might throw an error. Check status first.
if (response.status === 204) { // No Content
console.log('POST Success (No Content)');
return null;
}
const data = await response.json(); // Assuming the API returns JSON
console.log('POST Success:', data);
return data;
} catch (error) {
console.error('Error posting data:', error);
}
}
// Example usage:
const myData = { name: 'Example Item', value: 123 };
postData(myData);
Key Points:
Authorization: Bearer <token>
: This is the standard header format.YOUR_API_ENDPOINT
/YOUR_OAUTH_TOKEN
: Replace these placeholders with your actual values. Never hardcode sensitive tokens directly in your client-side JavaScript source code if it’s publicly accessible. Use environment variables on the server-side or secure configuration methods. If this is purely client-side, consider where the token is securely stored (e.g., memory, secure HttpOnly cookies if set by a server).method
: Change'GET'
to'POST'
,'PUT'
,'DELETE'
, etc., as needed by the API endpoint.Content-Type
: If you are sending data in the request body (like withPOST
orPUT
), you usually need to set theContent-Type
header (e.g.,'application/json'
) to tell the server what kind of data you’re sending.body
: ForPOST
orPUT
, you’ll add thebody
property. If sending JSON, remember to useJSON.stringify()
to convert your JavaScript object into a JSON string.Accept
: While often optional, setting'Accept': 'application/json'
is good practice to indicate that your client prefers to receive JSON data in the response.- CORS (Cross-Origin Resource Sharing): If you are making this request from a web browser to a different domain than the one your page is served from, the API server needs to be configured to allow requests from your origin (by sending the correct CORS headers). If not, the browser will block the request.
Error Handling
- Always check
response.ok
orresponse.status
before trying to parse the response body. - Handle potential network errors and non-successful HTTP statuses gracefully.
try { const response = await fetch(apiUrl, requestOptions); if (!response.ok) { // Get more error details if possible let errorData = null; try { // Try to parse error response body if server provides one errorData = await response.json(); } catch (parseError) { // Ignore if response body isn't JSON } const errorMessage = errorData?.error || 'An unknown error occurred' console.error('Server returned an error:', response.status, response.statusText, errorData); throw new Error(`HTTP error! Status: ${response.status}, ${errorMessage}`); } const data = await response.json(); console.log('Success (async/await):', data); // Process the data... return data; } catch (error) { console.error('Error fetching data (async/await):', error); // Handle the error appropriately (e.g., show a message to the user) }
Encapsulating it in a utility function
const authorizedFetch = async (url, options = {}) => {
const token = await getAccessToken()
const headers = {
...options.headers,
Authorization: Bearer ${token}`,
}
try {
const response = await fetch(url, init: { ...options, headers })
if (!response.ok) {
const errorData = await response.json()
const errorMessage = errorData?.error || "An unknown error occurred"
setSnackbarText (errorMessage)
throw new Error(errorMessage)
}
return await response.json()
} catch (error) {
console.error("Error in authorized Fetch: ", error)
throw error // Re-throw the error for further handling if needed
}
}
How to call this?
// Post example
const fetchRequestUsingPost = async (programModuleReq) => {
try {
const data = await authorizedFetch(`${apiUrl}/pathUrlForPost`, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(programModuleReq),
})
return data
} catch (error) {
console.error("Error posting request:", error)
throw error
}
}
// Get example
const fetchRequestUsingGet = async () => {
try {
const data = await authorized Fetch(${apiUrl}/pathUrlForGet`)
return data
} catch (error) {
console.error("Error fetching data:", error)
}
}
Notes:
- In order for this to work well, the backend applications have to implement a good error handling solution. They should wrap the errors in a json response and put the specific error details in a field called
error
in theresponse
- This error handling approach swallows all errors. Meaning, it will not pass the errors down to the individual functions making the fetch calls. That is a pro or a con depending on whether the individual functions need other details from the response (like response.status) instead of just getting
data
from theresponse
.