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": "*",
Related
I'm trying to programmatically add a role to a user to indicate their account as 'linked' or 'verified' in relation to my web app. To do so, I take the following steps:
in the frontend, send the user to the authorization url to authorize discord
when authorized, discord returns to my redirectURI, which calls my /discord/callback route
in this route, I get an access_token for the user from /oauth2/token
with the access_token, I get the discord_user object from /users/#me/guilds/${GUILD_ID}/member
So far, all of those requests are successful, and I get the data I expect. However, when I try to PATCH the user, and add a new role, for some reason I get a 401 unauthorized error, and I'm not entirely sure why. The endpoint I'm using is: https://discord.com/developers/docs/resources/guild#modify-guild-member
Here's my code for clarity:
const GUILD_ID = '<removed>';
const redirectURI = 'http://localhost:8000/auth/discord/callback';
const encodedRedirectURI = encodeURIComponent(redirectURI);
const url = `https://discord.com/api/oauth2/authorize?response_type=code&client_id=${process.env.DISCORD_CLIENT}&scope=identify%20guilds.members.read%20guilds.join&redirect_uri=${redirectURI}&prompt=consent`
router.get('/discord/callback', async (req, res) => {
const { code } = req.query;
try {
const params = new URLSearchParams();
params.append('grant_type', 'authorization_code');
params.append('client_id', process.env.DISCORD_CLIENT);
params.append('client_secret', process.env.DISCORD_SECRET);
params.append('code', code);
params.append('redirect_uri', 'http://localhost:8000/auth/discord/callback');
let access_token;
try {
const tokenRequest = await fetch(`https://discord.com/api/v8/oauth2/token`, {
method: 'POST',
body: params,
headers: {
'Content-type': 'application/x-www-form-urlencoded'
}
}).then(r => r.json());
access_token = tokenRequest.access_token;
} catch {
throw new Error('Failed to get access token.');
}
let discord_user;
try {
discord_user = await fetch(`https://discord.com/api/v8/users/#me/guilds/${GUILD_ID}/member`, {
method: 'GET',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${access_token}`
}
}).then(r => r.json());
} catch {
throw new Error('Failed to get user from guild');
}
const discord_user_id = discord_user.user.id;
try {
await fetch(`https://discord.com/api/v8/guilds/${GUILD_ID}/members/${discord_user_id}`, {
method: 'PATCH',
body: JSON.stringify({
roles: [
'foo',
...discord_user.roles
],
}),
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${access_token}`
}
}).then(r => r.json())
.then((data) => {
console.log(data); // 401 unauthorized
});
} catch {
throw new Error('Failed to add role to user');
}
return res.redirect('/settings?state=success');
} catch {
return res.redirect('/settings?state=failure');
}
});
Figured it out:
The role needs to be the ID of the role, not the name of the role, e.g.: '957197947676803072' instead of 'foo'
The role setting needs to be done by a bot:
await fetch(`https://discord.com/api/v8/guilds/${GUILD_ID}/members/${discord_user_id}`, {
method: 'PATCH',
body: JSON.stringify({
roles: ['957197947676803072', ...discord_user.roles]
}),
headers: {
'Content-Type': 'application/json',
'Authorization': `Bot ${process.env.DISCORD_BOT_TOKEN}`
}
}).then(r => r.json())
I also needed to give that bot account admin permissions and manage roles permissions. You can do this either in the invite link or in your discord's server settings.
Every time NextJs request for an api, it will come first to api routes before it redirected to my RoR backend service.
I use this to encrypt my access token to session NextJS using iron-session once I get the data from backend.
## src/pages/api/login.ts
const loginRoute = async (req: NextApiRequest, res: NextApiResponse) => {
const response = await fetch(`backend-service/authorizations.json`, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
username: req.body.username,
password: req.body.password
})
})
.then((res) => {
if (!res.ok) {
return res.text().then((text) => {
throw new Error(text)
})
}
return res
})
.then((res) => res.json())
.catch((err) => {
res.status(401).json({ message: err })
})
if (response) {
req.session.user = response
await req.session.save()
res.json(response)
}
}
export default withSessionRoute(loginRoute)
Is this a valid use case for API Routes in NextJS?
Thanks in advance!
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()
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();
}
I've run into issue where I can't get confirmation that user is authenticated from ExpressJS backend. I am using PassportJS with Google OAuth2.
When I try to access my API endpoint through browser, it returns the data I need. Why is this so? Is there a problem with cors and backend or with my request?
This is the error I get after a while on the same page: GET http://localhost:5000/api/auth/login/success net::ERR_EMPTY_RESPONSE
Here is my request:
useEffect(() => {
const fetchData = async () => {
await axios
.get(`${API_URL}/auth/login/success`, {
headers: {
Accept: "application/json",
"Content-Type": "application/json",
"Access-Control-Allow-Credentials": true,
},
})
.then((response) => {
if (response === 200) {
console.log(response);
console.log("200");
return response.json();
}
throw new Error("Failed to authenticate the user.");
})
.then((responseJson) => {
userHasAuthenticated(true);
setUser(responseJson.user);
console.log("responseJson");
setLoading(false);
})
.catch((error) => console.log(error));
};
fetchData();
}, [loading]);
I dont't get any outputs to the console.
Here is my route on the backend:
router.get("/login/success", (req, res) => {
console.log(req.user);
console.log("/login/success");
if (req.user) {
res.json({
success: true,
message: "User has successfully authenticated.",
user: req.user,
cookies: req.cookies,
});
}
});
When I try to access this route on my browser, I see the response and it prints it out in the console. But when I visit the frontend page from where the request is sent, nodejs console prints out undefined.