I enabled CORS, but still getting restricted - reactjs

This is my configuration in asp.net core web API:
public void ConfigureServices(IServiceCollection services)
{
services.AddCors(o => o.AddPolicy("CorsPolicy", builder =>
{
builder
.AllowAnyOrigin()
.AllowAnyMethod()
.AllowAnyHeader();
}));
and
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.UseCors("CorsPolicy");
And finally my javascript (typescript react):
const requestOptions = {
method: 'POST',
mode: 'cors' as RequestMode,
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ Username: username, Password: password })
};
return fetch(`${this.baseUrl}/auth/register`, requestOptions).then(res => {
debugger;
if (res.ok === false) {
return Promise.reject("Invalid request");
}
return res.json();
});
I can't figure it out. I've tried changing the mode on the client-side. I've tried.WithOrigins("http://localhost:3000") in the API and I'm now out of luck. What am I missing here? I ran my react app with npm start, is that it? Should not be?
Response:
Request URL: https://localhost:44346/auth/register
Request Method: POST
Status Code: 404
Remote Address: [::1]:44346
Referrer Policy: strict-origin-when-cross-origin
The response headers:
access-control-allow-origin: *
date: Thu, 17 Dec 2020 22:23:37 GMT
server: Microsoft-IIS/10.0
x-powered-by: ASP.NET

The order of middlewares is important.
In your Configure() method first add app.UseRouting(); and after that app.UseCors("CorsPolicy");

try to remove
mode: 'cors' as RequestMode
from your javascript
and instead of
body: JSON.stringify({ Username: username, Password: password })
use
body: { Username: username, Password: password }

import { ExpectedConditions as EC, browser, by, element } from 'protractor';
// ...
async function getTextFromClipboard() {
// ...
await browser.wait(
EC.visibilityOf(element(by.css('.btn-copy'))),
waitTimeout
);
await element(by.css('.btn-copy')).click();
}

Related

React/Rails Stack with Devise Gem and ActiveStorage - How to Add Profile Picture?

For my project, I'm trying to add a profile picture, sent from a React frontend to a Rails API backend by leveraging ActiveStorage. I'm already using the devise and devise-jwt gems for authentication.
I'm having trouble understanding how to customize the devise user create action, user Model, and user_controller to accept a profile picture. I can set up the ActiveStorage migrations and run them fine.
The other main issue is how to customize my POST request from my React frontend. The guides linked above (and from my other searches) indicate that I need to create a new FormData object and should not specify a 'Content-Type' header since the FormDataAPI will handle everything so we post this in the body of the request like this:
`
fetch('http://localhost:3000/posts', {
method: 'POST',
body: formData
})
`
However, the way I have it set up in my frontend React code is formatted like this so that the devise gem on my Rails API backend will understand where to get what data to create a user:
`
fetch("http://localhost:3000/signup", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
user: {
username: username,
email: email,
password: password,
}
})
`
Where the body is stringified with the JSON Object:
`
{
user: {
username: username,
email: email,
password: password,
}
}
`
I'm having trouble reconciling this with the devise gem in my Rails API backend and haven't found a way to integrate this so I need a way to customize the create action in the devise registration controller to include a profile picture association in ActiveStorage.
So far my Rails controllers looks like this:
`
class Users::RegistrationsController < Devise::RegistrationsController
respond_to :json
rescue_from ActiveRecord::RecordNotFound, with: :render_not_found_response
rescue_from ActiveRecord::RecordInvalid, with: :render_unprocessable_entity_response
rescue_from JWT::ExpiredSignature, with: :expired_token_response
private
def respond_with(resource, _opts = {})
if resource.persisted?
render json: {
status: {code: 200, message: 'Signed up sucessfully.'},
# data: UserSerializer.new(resource).serializable_hash[:data][:attributes]
data: UserSerializer.new(resource)
}
else
render json: {
status: {message: "User couldn't be created successfully. #{resource.errors.full_messages.to_sentence}"}
}, status: :unprocessable_entity
end
end
end
`
And my routes.rb for users looks like this:
`
devise_for :users, path: '', path_names: {
sign_in: 'login',
sign_out: 'logout',
registration: 'signup'
},
controllers: {
sessions: 'users/sessions',
registrations: 'users/registrations'
}
`
I've tried reformatting my frontend fetch request like this:
`
async function exampleSubmit(e) {
e.preventDefault();
setLoading(true);
const form = document.getElementById('sign-up-form');
const formData = new FormData(form);
const userObj = {
username: formData.get('username'),
email: formData.get('email'),
password: formData.get('password'),
};
let photoInput = document.getElementById('profile-photo-input');
if (photoInput.files[0]) {
const uploadedPicture = photoInput.files[0];
userObj['profilePicture'] = uploadedPicture;
}
await fetch("http://localhost:3000/signup", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
user: userObj
}),
})
.then(res => res.json())
.then((data) => {
console.log(data);
});
}
`
I'm wondering if this will work as well:
`
async function exampleSubmit(e) {
e.preventDefault();
setLoading(true);
const form = document.getElementById('sign-up-form');
const formData = new FormData(form);
let photoInput = document.getElementById('profile-photo-input');
if (photoInput.files[0]) {
const uploadedPicture = photoInput.files[0];
formData.append('profilePicture', uploadedPicture);
}
await fetch("http://localhost:3000/signup", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
user: formData
}),
})
.then(res => res.json())
.then((data) => {
console.log(data);
});
}
`
Or if this will throw an error in the backend if Rails cannot recognize the formData in their params when receiving the POST request.
As for the Rails API Backend, I need some help in understanding how to customize the user with strong params to incl an ActiveStorage association + a way to give someone a default profile picture.
Thanks so much!

POST preflight Request get rejected with 403 status code

I´m trying to make a POST request to my API, but the CORS policy is blocking the request in the preflight.
I already configured my back-end to accept requests from the front-end origin and to allow all the methods (including OPTIONS and POST).
Here´s my Spring CORS Configuration:
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**").allowedOrigins("https://brazilnews.herokuapp.com", "http://localhost:3000")
.allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS", "HEAD", "TRACE", "CONNECT")
.allowedHeaders("append,delete,entries,foreach,get,has,keys,set,values,Authorization")
.allowCredentials(true);
}
Axios Request:
export const api =
axios.create({
baseURL: "http://localhost:8080",
headers: {
"Content-Type": "application/json"
}
});
export const auth = async (email, senha) => {
const body = {
email: email,
senha: senha
}
const res = await api.post("/auth", body)
.then(res => {
console.log(res.data);
}).catch(err => {
console.error(err);
});
return res;
}
Request/Response details:
Console
Solved it by adding this line in the SecurityConfigurations
antMatchers(HttpMethod.OPTIONS, "/**").permitAll()

firebase authentication rest API request with axios

I am trying to write function to Sign in user with Email and Password.
Using Axios and firebase rest API.
So this is how Axios instance looks like, really simple right? ...
const authUrl = `https://identitytoolkit.googleapis.com/v1/accounts:signInWithPassword?key=${DATABASE_SECRET}`;
const baseURL = "https://beauty-wonderland-e913c-default-rtdb.firebaseio.com";
export const getAxios = (token = null) => {
const config = {
baseURL: baseURL,
headers: {
"Content-Type": "application/json",
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Methods": "DELETE, POST, GET, OPTIONS",
"Access-Control-Allow-Headers":
"Content-Type, Access-Control-Allow-Headers, Authorization, X-Requested-With",
},
timeout: 10000,
};
if (token !== null) {
// config.headers.Authorization = `Bearer ${token}`;
config.baseURL = authUrl;
config.withCredentials = true;
}
let instance = axios.create(config);
instance.interceptors.request.use(
(request) => {
return request;
},
(error) => {
console.log("axios error: ", error);
return Promise.reject(error);
}
);
instance.interceptors.response.use((response) => {
return response;
});
return instance;
};
This code works fine, flexible and can send any kind of request, but when it comes to authentication, there is problem with sending user data: email and password.
const loginHandler = async () => {
const response = await getAxios("/").post("", {
body: JSON.stringify({
email: "example#example.com",
password: "password",
returnSecureToken: true,
}),
});
const outPut = processResponse(response);
console.log(outPut);
}
so as i guess There is problem with this part
{
body: JSON.stringify({
email: "a#a.com",
password: "123456",
returnSecureToken: true,
}),
});
}
if fetch function works this way
fetch(
`https://identitytoolkit.googleapis.com/v1/accounts:signInWithPasswordkey=${DATABASE_SECRET}`,
{
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
email: "example#example.com",
password: "password",
returnSecureToken: true,
}),
}
);
why do axios gives following error:
XMLHttpRequest at ... from origin 'http://localhost:19006' 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.
Please note other get and post request with axios works, and alo authentication works with fetch, only axios shows such an error, please post additional resourses to learn more about firebase rest API and Axios usecases.
This is how error looks like
The baseURL in the axios instance returned by "getAxios" function is https://beauty-wonderland-e913c-default-rtdb.firebaseio.com and not the Auth REST API url. It should be authUrl instead. While in fetch you have hard-coded the URL so the URL is correct for sure.
Edit:
Remove those extraneous headers. You just need content-type as per the docs. I got the same CORS error when I had those.
const config = {
baseURL: baseURL,
headers: {
"Content-Type": "application/json",
},
timeout: 10000,
};

Asp.net Core: Cross-Origin Request Blocked

I am using react as a front-end and asp.net core as a back-end. I am using fetch API for API request but I am getting Cors error on the browser console saying: Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at https://localhost:44316/api/auth/register. (Reason: CORS request did not succeed).
My ConfigureServices method is:
public void ConfigureServices(IServiceCollection services)
{
services.AddCors(options =>
{
options.AddPolicy("myPolicy", builder =>
{
builder.WithOrigins("http://localhost:3000")
.AllowAnyHeader()
.AllowAnyMethod()
.AllowCredentials();
});
});
services.AddSignalR();
services.AddDbContext<UserContext>(options => options.UseSqlServer(Configuration.GetConnectionString(name: "Default")));
services.AddControllers();
services.AddScoped<IUserRepository, UserRepository>();
services.AddScoped<IJwtHelper, JwtHelper>();
}
And the Configure method is:
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseRouting();
app.UseCors("myPolicy");
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
endpoints.MapHub<ChatHub>("/chat");
});
}
In react I created a form submit event and its looks like:
const submitRegisterForm = async (e) => {
e.preventDefault();
await fetch(
"https://localhost:44316/api/auth/register",{
method: 'POST',
headers: {"Content-Type": "application/json"},
body: JSON.stringify({
name,
email,
password,
role,
})
});
setRedirectTo(true);
};
This the output I am getting in Brower network tab:
Try as follows
In your ConfigureServices method
services.AddCors(options =>
{
options.AddPolicy("ClientPermission", policy =>
{
policy.AllowAnyHeader()
.AllowAnyMethod()
.SetIsOriginAllowed(_ => true)
.AllowCredentials();
});
});
and in your Configure method
app.UseCors("ClientPermission");
On the client side for localhost request use http and not https
const submitRegisterForm = async (e) => {
e.preventDefault();
try {
const res = await fetch(
"http://localhost:44316/api/auth/register",{
method: 'POST',
headers: {"Content-Type": "application/json"},
body: JSON.stringify({
name,
email,
password,
role,
})
});
setRedirectTo(true);
}
catch(err){
console.log(err)
}
};
The placement order codes in asp.net core v6 should be as follows in program.cs
app.UseCors(builder => builder
.AllowAnyOrigin()
.AllowAnyMethod()
.AllowAnyHeader());
app.UseAuthentication();
app.UseAuthorization();
Also in front and in jsx you should send the headers as follow:
"Content-Type": "application/json",
"Accept": 'application/json',
"authorization": "Bearer " + token,
"Access-Control-Allow-Origin": "*",

Set cookie from API response in React

I have a React app, and an API. When i POST data to APIs login url API responses me back with cookie on successful login, which I have to set, so in each next request user will send this cookie. But I can't find a method to get it from response.
I want to set sessionid, but I can't reach it within code. I tried to do
Cookies.set('sessionid', response.headers['sessionid']);
But it sets undefined. console.log(response.headers) also gives me {content-length: "31", content-type: "application/json"}. Do I do something wrong?
Sender function:
formSender() {
const url_to_send = `${this.state.api_base_url}:${this.state.api_base_port}${this.state.api_user_url}/login/`;
axios.post(url_to_send, `username=${this.state.username}&password=${this.state.password}`, {headers: {'Content-Type': 'application/x-www-form-urlencoded'}})
.then((response) => {
// I need to set the cookie here
this.setState({
login_success: response.status === 200,
request_sent: false
});
})
};
Try to set Access-Control-Expose-Headers in the back end or
await axios({
method: 'post',
url: YOUR_URL,
data: Data,
headers: { 'Authorization': 'TOKEN' }
});
I have the same problems and i do that for resolve in backend:
app.use(cors({
origin: true,
credentials: true
}));
and the axios request :
axios({
method: "post",
url: `http://localhost:5500/api/user/login`,
withCredentials: true,
data: {
email,
password,
},
headers: {
"Content-Type": "application/json",
}
})
.then((res) => {
console.log(res);
})
I was initially looking for a solution to setting a cookie from a response, but I realized if it's passed as a Set-Cookie header then it is set by the browser. No need to set it manually. Here is the console view
My app looks something like this:
const app = express();
app.use(cors({
origin: ['http://localhost:3000'],
methods: ['POST', 'PUT', 'GET', 'OPTIONS', 'HEAD'],
credentials: true,
}))
app.use(cookieParser())
app.get('/foo', verifyToken, (req, res) => {
// you can omit verifyToken if you want, it's for bearer auth.
if (true) {
res.cookie('XSRF-TOKEN', 'example')
res.send('Welcome')
} else {
res.sendStatus(403);
}
});
The React side:
<Button onClick={() => {
axios.get('http://localhost:8081/foo', {
params: {},
headers: {
Authorization: `Bearer 123`,
// again, omit ^ if you're not doing bearer auth
},
withCredentials: true,
}
).then((response) => {
console.log('cookie should be set')
})
}}>Express cookie</Button>
Bear in mind if you're deploying to a server both react and express should be on an https connection. Connecting http <-> https causes other issues with cookies.

Resources