Stack : ReactJS, axios , api deployed on AWS
In My reactjs App, I am calling API deployed on aws using axios. This app is working perfectly in chrome and firefox, But failing in IE 11.
All apis are correctly configured to allow Authorization in access control header
I am using below code to add authorization header and accessToken in a request
const axiosInstance = axios.create({
baseURL: `https://abc.api.nonprod.org/`
});
export const createTokenHeaders = (idToken, accessToken) => ({
authorization: `Bearer ${idToken}`,
accessToken: `Bearer ${accessToken}`
});
// Add a request interceptor
export const reqInterceptor = config =>
// get the bearer token and add it in the header
Auth.currentSession()
.then(data => {
const idToken = data.getIdToken().getJwtToken();
const accessToken = data.getAccessToken().getJwtToken();
// eslint-disable-next-line no-param-reassign
config.headers = Object.assign({}, config.headers, createTokenHeaders(idToken, accessToken));
return config;
})
.catch(err => {
console.log(err);
throw new Error('Error getting bearer token');
});
axiosInstance.interceptors.request.use(reqInterceptor);
export const performGet = (uri, queryParams = {}, headers) => {
const requestParams = {
params: queryParams,
headers
};
return axiosInstance.get(uri, requestParams);
};
When I run this app in chrome from localhost:3000 then chrome is correctly calling OPTIONS request and then GET request with correct Authorization header.
But when I am running the same app in IE it is not calling OPTIONS request and also not passing Authorization header in GET request( however it is passing accessToken header).
Is you IE running on enhanced protection mode?
It does not seem to be code issue.
https://www.npmjs.com/package/react-native-axios
react-native-axios support IE11.
use f12 debugger and check for not found url in network traffic.
You probably need to set withCredentials: true in order for authorization headers to be passed to CORS requests.
Related
I'm playing around with the Spotify Web API, and I'm trying to fetch my most played songs. I'm using the client credentials OAuth flow (you can read more about it at https://developer.spotify.com/documentation/general/guides/authorization/client-credentials/) to get an access token so that I can create requests. I'm getting the access token just fine, but when I try to fetch the data with the token, I'm getting a 403, indicating that my request is not being authorized.
Error code:
GET https://api.spotify.com/v1/me/top/tracks 403
I'm using React, so I'm fetching the data on page load with useEffect.
API File (spotify.ts)
import { Buffer } from 'buffer';
const clientId = "" // omitted for privacy
const clientSecret = "" // omitted for privacy
const getToken = async (): Promise<string> => {
const res = await fetch('https://accounts.spotify.com/api/token', {
method: 'POST',
headers: {
'Authorization': 'Basic ' + Buffer.from(clientId + ':' + clientSecret).toString('base64'),
'Content-Type': 'application/x-www-form-urlencoded',
},
body: new URLSearchParams({
grant_type: 'client_credentials',
scope: 'user-top-read',
}),
});
const data = await res.json();
return data.access_token;
};
const getMostRecentSong = async (token: string) => {
const res = await fetch('https://api.spotify.com/v1/me/top/tracks', {
headers: {
'Authorization': `Bearer ${token}`,
},
});
const data = await res.json();
return data;
}
App.tsx
import React, { useEffect } from 'react'
import { getToken, getMostRecentSong } from './services/spotify'
const App = () => {
useEffect(() => {
const getData = async () => {
const accessToken = await getToken();
const data = await getMostRecentSong(accessToken);
console.log(data);
}
getData();
}, [])
return (
...
)
}
I've included my App.tsx file as well for convenience, but the only error I'm getting is with the request itself. Any help is greatly appreciated :)
The /me/top/{type} route requires the user-top-read scope, so using the Client Credentials flow will always result in an error. Here's a summary of the Client Credentials flow:
The Client Credentials flow is used in server-to-server authentication. Since this flow does not include authorization, only endpoints that do not access user information can be accessed.
Instead, you will need to use the Authorization Code flow and proxy the Spotify requests using a request mechanism that isn't restricted by CORS (e.g. a server or serverless function), or use the Implicit Grant flow which can be implemented without an additional cooperating process (you can do it all in your client React app).
I am currently working on a project using Ionic React with .NET API for login process.
And this is the problem I am facing:
This is the Response Header of my post request
And when I try to look at the application cookie, it seems that it is not being set.
This is the application view which should see the jwt cookie has been stored.
I have already added these two params for my Axios post request but not work at all.
{withCredentials: true, credentials: 'include'}
Thank you for your time to look into my question or help!!!
Below are my request/response setting on the client-side and backend:
Axios request:
const api = axios.create({
baseURL: `https://localhost:7220/api/User`
})
api.post("/login", postData, {withCredentials: true, credentials: 'include'})
.then(res => {
console.log(res);
})
.catch(error=>{
console.log(error);
})
Controller:
Response.Cookies.Append(key: "jwt", value: token, new CookieOptions
{
HttpOnly = true
});
Response response = new Response { Status = true, Message = _LOGINSUCCESSFUL };
return Ok(response);
Program.cs:
builder.Services.AddCors(p => p.AddPolicy("corsapp", builder =>
{
builder.WithOrigins("http://localhost:3000").AllowCredentials().AllowAnyMethod().AllowAnyHeader().AllowAnyMethod();
}
)
);
I am trying to get basic information from Vimeo API about searched video by it's ID
I have Token Client Identifier and Secrets but Api documentation is pretty complicated
The question is how to make a simple call to fetch data?
I already tried with axios:
const GetByIdVimeo = async (ID) => {
const Token = 'MY_TOKEN'
const response = await axios.get({
url: `https://api.vimeo.com/videos/${ID}`,
Authorization: `bearer ${Token}`
}
)
const mofifiedResponse = {
resp: response
}
return mofifiedResponse
}
export default GetByIdVimeo
But response is 404 not Found status rejected
Thanks for help
The following code works.
First argument of axios.get() method is the url and the second a configuration object where you can specify your headers property. There you should place your authorization token.
const GetByIdVimeo = async (ID) => {
const Token = "YOUR_TOKEN";
const response = await axios.get(`https://api.vimeo.com/videos/${ID}`, {
headers: {
Authorization: `Bearer ${Token}`,
},
});
const mofifiedResponse = {
resp: response,
};
return mofifiedResponse;
};
export default GetByIdVimeo
Keep in mind that you have to generate an unauthenticated access token to access data this way. Otherwise you have to use OAuth to authenticate, which may be more complicated.
I'm a frontend developer trying to create a test case of adding google-recaptcha-v3 in my react app.
I'd appreciate response to how i can by-pass the cors error when I make a post request to verify the user's token.
//imports
...
const Recaptcha=()=>{
return(
<div>
<p>Recaptcha Test</p>
<button onClick={handleSubmit}>Send Test</button>
</div>
)
// handleSubmit function
const handleSubmit =()=>{
const getToken = async () => {
await executeRecaptcha('contactpage')
.then(res=>{
console.log(res);
return setToken(res);
});
}
getToken();
console.log(token);
const verifyToken = async () => {
console.log(token);
const article = {
secret: '*******',
response: token
}
let axiosConfig = {
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
"Access-Control-Allow-Origin": "http://localhost:3000",
}
};
let url = 'https://www.google.com/recaptcha/api/siteverify';
await axios.post(url, article)
.then(res => console.log(res))
.catch(err => console.log(err));
}
verifyToken();
}
Then I get this error in my browser console:
Access to XMLHttpRequest at 'https://www.google.com/recaptcha/api/siteverify' from origin 'http://localhost:3000/' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.
Google is not allowing you to call 'https://www.google.com/recaptcha/api/siteverify' from a frontend because of their CORS policy. See Mozilla's CORS guide for more information about CORS. Calls can only be initiated from a backend and not from a browser.
The Setup
I have setup a frontend environment using create-react-app. In this environment I use Axios to make a POST request to my Node JS Express Backend Server /login endpoint. I setup sessions middleware using express-sessions and storing the sessions in Redis. I have all this running in localhost currently.
Environment
React App - http://localhost:3005/kp (Note: the service runs on
http://localhost:3005 however, all the routes have /kp in them)
Express Backend - http://localhost:5001
Redis - http://localhost:6379
What Works
When the frontend sends the request to the backend the Express server does it's thing and authenticates the user; it stores the username in the req.session.username (this is just as a test), Redis console shows that the key value store was successful, the frontend network tab shows a 200 status with a Set-Cookie response header and a tab that shows the cookie (screenshots below).
The Problem
Everything seems to be working fine but the cookie is not set in the Browser. I have refreshed the page, tried again many times and yet it will not set the cookie in any browser (Google Chrome & Safari). I am getting frustrated because it seems as though Chrome acknowledges that the Set-Cookie is present but ignores it for some reason.
What I've Tried
Axios
I have tried setting withCredentials: true - Does not work
Verified the cookie with Set-Cookie is being sent back to the frontend after the POST request
Backend
I have checked my CORS policies to but they seem fine; however, I am not great with CORS so there could be misconfiguration there
Tried setting credentials to true in CORS policy
Verified the session with variables are being set with Redis.
Code
React Frontend Axios POST Request
axios.post('http://localhost:5001/login', loginBody, {
headers: {
'Content-Type': 'application/json'
}
},
{ withCredentials: true }
)
.then((res) => {
console.log(res);
})
.catch((error) => {
console.log(error);
this.setState({
errorMessage: `Server Error`,
loading: false
});
});
Express Server
const express = require('express');
const http = require('http');
const cors = require('cors');
const socketServer = require('./src/sockets');
const bodyParser = require('body-parser');
const session = require('express-session');
const redis = require('redis');
const redisClient = redis.createClient();
const redisStore = require('connect-redis')(session);
process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0";
const port = process.env.PORT || 5001;
const { loginRoutes } = require('./src/routers');
const app = express();
redisClient.on('error', (err) => {
console.log('Redis error: ', err);
});
app.use(cors({
origin: '*',
methods: ['POST', 'PUT', 'GET', 'OPTIONS', 'HEAD'],
credentials: true
}));
// Redis session storage setup
// API Docs for express-session: https://www.npmjs.com/package/express-session
const sessionMiddleware = session({
secret: process.env.REDIS_SECRET || 'testing12345',
name: 'session',
resave: false,
saveUninitialized: true,
cookie: {
secure: false
},
store: new redisStore(
{
host: process.env.REDIS_HOSTNAME,
port: process.env.REDIS_PORT,
client: redisClient,
ttl: 604800
}
)
});
// Uses session middleware
app.use(sessionMiddleware);
app.use(bodyParser.json({ limit: '5mb' }));
const server = http.createServer(app);
// Starts Socket Server
socketServer(server, sessionMiddleware);
// Uses the routes from the router directory
app.use(loginRoutes);
server.listen(port, () => {
console.log(`Listening on port: ${port}`);
});
Screenshots
Network Response
Request Cookie
Application Cookies
As you can see the cookie is missing in the list of browser cookies. I have a feeling it is something small but I have not been able to find anything.
I am not getting any errors in any service. Thank you in advance for your help.
Solution
As MichaĆ Lach pointed out I put withCredentials in the wrong place in the Axios call.
Frontend Axios
axios.post('http://localhost:5001/login', loginBody, {
headers: {
'Content-Type': 'application/json'
},
withCredentials: true
})
However, once I did this I began to get CORS error. The CORS error was you cannot have a wildcard '*' in your Access-Control-Allow-Origin (origin) configuration. For this example I changed it to point only to http://localhost:3005; however, there are ways to do dynamic whitelists as documented here: https://www.npmjs.com/package/cors#configuring-cors-w-dynamic-origin
Backend
app.use(cors({
origin: 'http://localhost:3005',
methods: ['POST', 'PUT', 'GET', 'OPTIONS', 'HEAD'],
credentials: true
}));
Once I made these changes the cookie started being set on the frontend correctly.
Are you sure, you are setting axios options correctly ?
You have :
axios.post('http://localhost:5001/login', loginBody, {
headers: {
'Content-Type': 'application/json'
}
},
{ withCredentials: true }
)
.then((res) => {
console.log(res);
})
.catch((error) => {
console.log(error);
this.setState({
errorMessage: `Server Error`,
loading: false
});
});
Try this:
axios.post('http://localhost:5001/login', loginBody, {
headers: {
'Content-Type': 'application/json'
},
{ withCredentials: true }
}
....