REST API error "CORS preflight channel did not succeed" - angularjs

I created a RESTapi to insert data into my databse, It's working perfectly on POSTMAN extension, but I'm getting an error on angularjs http post method.
My Restapi code is created in yii2 framework. My code is below,
public function actionNew()
{
$model = new Apieducation();
$user_id = $_REQUEST['user_id'];
$education = $_REQUEST['education'];
$passing_year = $_REQUEST['passing_year'];
$institute = $_REQUEST['institute'];
//$model->attributes=$params;
$model->user_id = $user_id;
$model->education = $education;
$model->passing_year = $passing_year;
$model->institute = $institute;
if ($model->save()) {
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Methods: GET, POST');
header("Access-Control-Allow-Headers: X-Requested-With,content-type");
echo json_encode(array('status'=>'1','data'=>$model->attributes),JSON_PRETTY_PRINT);
\Yii::$app->response->format = \yii\web\Response::FORMAT_JSON;
}
else
{
$jobs[] = 'failed';
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Methods: GET, POST');
header("Access-Control-Allow-Headers: X-Requested-With,content-type");
echo json_encode(array('status'=>'1','data'=>array_filter($jobs)),JSON_PRETTY_PRINT);
\Yii::$app->response->format = \yii\web\Response::FORMAT_JSON;
}
}
And My Angularjs function code is,
$scope.educationcreate = function() {
var data = $.param({
user_id: $scope.data.user_id,
education: $scope.data.education,
passing_year: $scope.data.passing_year,
institute: $scope.data.institute
});
var config = {
headers : {
'Content-Type': 'application/x-www-form-urlencoded;charset=utf-8;'
}
};
$http.post('http://localhost/basic/web/index.php?r=apieducation/new', data, config)
.success(function(data, status, headers, config) {
alert('Successfully');
})
.error(function(data, status, headers, config) {
alert("ERROR");
});
};
I got console error,
Cross-Origin Request Blocked: The Same Origin Policy disallows reading
the remote resource at
http://localhost/basic/web/index.php?r=apieducation/new. (Reason: CORS
preflight channel did not succeed).
How can I solve it?

Using the Cors filter to solve this error,
public function behaviors()
{
return [
'corsFilter' => [
'class' => Cors::className(),
'cors' => [
// restrict access to
'Origin' => ['*'],
'Access-Control-Request-Method' => ['POST', 'GET'],
// Allow only POST and PUT methods
'Access-Control-Request-Headers' => [' X-Requested-With'],
// Allow only headers 'X-Wsse'
'Access-Control-Allow-Credentials' => true,
// Allow OPTIONS caching
'Access-Control-Max-Age' => 3600,
// Allow the X-Pagination-Current-Page header to be exposed to the browser.
'Access-Control-Expose-Headers' => ['X-Pagination-Current-Page'],
],
],
];
}

My short solution:
On server side:
npm install cors
add app.use(cors({origin: '*'})); before all route definitions
On client side:
do everything normally
$http.get('http://localhost:36912/api/permissions').then(function (response) {
console.log(response);
})
.catch(function (error) {
console.error('Status code: ' + error.status);
console.error('Error message: ' + error.data);
});

Related

How to enable CORS for .NET API

I have an application with React front-end and .NET as API using fetch.
In App.js I have:
var myHeaders = new Headers();
myHeaders.append("Content-Type", "application/json");
myHeaders.append('Access-Control-Allow-Origin', '*');
myHeaders.append('Access-Control-Allow-Credentials', 'true');
var raw = JSON.stringify({
"userText": e.target.value
});
var requestOptions = {
method: 'POST',
headers: myHeaders,
body: raw,
redirect: 'follow',
};
fetch("https://localhost:7101/api/Game/UserText", requestOptions)
.then(response => response.text())
.then(result => console.log(result))
.catch(error => console.log('error', error));
and for my controller:
[HttpPost]
[Route("UserText")]
public IActionResult GetUserText([FromBody] UserText userText)
{
Console.WriteLine(userText.userText);
return Ok();
}
and in program.cs:
var MyAllowSpecificOrigins = "_myAllowSpecificOrigins";
builder.Services.AddCors(options =>
{
options.AddPolicy(name: MyAllowSpecificOrigins,
policy =>
{
policy.WithOrigins("*");
});
});
app.UseCors(MyAllowSpecificOrigins);
I have tried a few things but the error is always the same. Also tried to install the extension for Chrome but the error also stays.
The error message is:
Access to fetch at 'https://localhost:7101/api/Game/UserText' 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. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
:7101/api/Game/UserText:1
Failed to load resource: net::ERR_FAILED
You have not provided the error anywhere, but I assume its CORS error you are talking about.
Have you tried allowing all Headers, Methods etc as below?
var MyAllowSpecificOrigins = "_myAllowSpecificOrigins";
builder.Services.AddCors(options =>
{
options.AddPolicy(name: MyAllowSpecificOrigins,
policy =>
{
policy.WithOrigins("*")
.AllowAnyHeader()
.AllowAnyMethod()
.AllowCredentials();
});
});
app.UseCors(MyAllowSpecificOrigins);
Note: If you have the specific values for these parameters, its always recommended to use them. For instance, instead of WithOrigins("*"), it should be the WithOrigins(urls) which should have access to the site.

I am trying to call a 3rd party api and it is giving me a CORS error

const https = require('https');
export async function main(event, callback) {
const options = {
method: 'GET',
host: 'https://api.challonge.com/v1/',
headers: {
'Access-Control-Allow-Methods': 'GET',
"api_key": "THE_KEY",
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Credentials": true
}
};
var dataString = " ";
const response = await new Promise((resolve, reject) => {
const req = https.get(options, function (response) {
response.on('data', chunk => {
dataString += chunk;
});
response.on('end', () => {
resolve({
statusCode: 200,
headers: {
"Access-Control-Allow-Origin": "*"
},
body: JSON.stringify((dataString))
});
});
});
req.on('error', (e) => {
reject({
statusCode: 500,
headers: {
"Access-Control-Allow-Origin": "*"
},
body: e.message
});
});
});
return response;
};
This is the lambda function ^
getChallongeTournaments:
handler: getChallongeTournaments.main
events:
- http:
path: tournaments/
method: get
cors: true
authorizer: aws_iam
my serverless.yml
// in a useEffect
function getChallongeTournaments(){
return API.get("byoc_users", '/tournaments.json');
}
async function onLoaded() {
try {
const testChallonge = await getChallongeTournaments();
^ The API call
According to the challonge docs this should receive 'Retrieve a set of tournaments created with your account.' and there is one created.
This is the CORS error I'm receiving: Access to XMLHttpRequest at 'https://m3heucf413.execute-api.us-east-2.amazonaws.com/prod/tournaments.json' from origin 'http://localhost:8100' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: It does not have HTTP ok status.
Preflight Requests and CORS flag is raised by the Browser when there is a request from a domain/port to an entire new domain/port. If you are doing this for testing, you can disable this security flag in chrome by adding the --disable-web-security flag. Just create a shortcut of chrome to desktop > Right click > Properties >In shortcut tab - Target > Append --disable-web-security --user-data-dir="C:\tmpChromeSession" to target. This will disable the CORS check.
If you have access/control on the 3rd party api server config, what you should be doing is to add necessary response headers (Access-Control-Allow-Origin) to the response. If you do not have access, one option will be to route the request through a CORS proxy.

401 unauthorized error when accessing protected controller, using passport and axios

I am using laravel 5.8 with preset react. Currently I am trying to workout authentication also I decided to use passport in backend and axios in fronend however I am getting this error when making axios request to protected controller AdminController#index
GET http://localhost:8000/api/admin/index 401 (Unauthorized)
I expected not to get it because I think I authenticated the user
I followed laravel passport instalation guide and now I am able to register, login user and get it's access token, but it seems that user logs out on new axios request because I get 401 error. Here is some context
in middleware I added this line
protected $middleware = [
\Laravel\Passport\Http\Middleware\CreateFreshApiToken::class,
]
//in AuthServiceProvider I added this and added Carbon because of error
Passport::routes(function ($router) {
$router->forAccessTokens();
$router->forPersonalAccessTokens();
$router->forTransientTokens();
});
Passport::tokensExpireIn(Carbon::now()->addMinutes(10));
Passport::refreshTokensExpireIn(Carbon::now()->addDays(10));
Passport::cookie('user_data');
In users model I added
use Notifiable, HasApiTokens;
//and
protected $primaryKey = 'id';
changed auth:api driver to passport
'api' => [
'driver' => 'passport',
'provider' => 'users',
'hash' => false,
],
this is my migration table
Schema::create('users', function (Blueprint $table) {
$table->bigIncrements('id');
$table->string('name')->unique();
$table->string('password');
$table->rememberToken();
$table->timestamps();
});
This is my login and register almost the same axios request
var bodyFormData = new FormData;
bodyFormData.append('name', this.state.name);
bodyFormData.append('password', this.state.password);
axios({
method: 'post',
url: '/api/login',
data: bodyFormData,
config: { headers: {'Content-Type': 'multipart/form-data' }}
})
.then(function (response) {
if(response.data.auth){
var cookies = new Cookies();
cookies.set('access_token', response.data.access_token, { path: '/' });
}
})
.catch(function (response) {
});
Here is my api routes:
//this one is to register using passport
Route::post('/register', 'AuthenticateController#register');
//this one is to login using passport
Route::post('/login', 'AuthenticateController#login');
//this one is to check if user is authenticated
Route::post('/check', 'AuthenticateController#test');
//this one has methods which I want to protect
Route::get('/admin/index', 'AdminController#index');
This is my AuthenticationController which gives me access token, registers and logins, seems to work
public function register(Request $request){
$validatedData = $request->validate([
'name' => 'required|max:55|unique:users',
'password' => 'required'
]);
$validatedData['password'] = bcrypt($request->password);
$user = User::create($validatedData);
$accessToken = $user->createToken('authToken')->accessToken;
return response()->json(["user" => $user, "token" => $accessToken]);
}
public function login(Request $request)
{
$loginData = $request->validate([
'name' => 'required',
'password' => 'required'
]);
if(!auth()->attempt($loginData, true)) {
return response(['auth' =>
false]);
}
$accessToken = auth()->user()->createToken('authToken')->accessToken;
return response(['user' => auth()->user(), 'access_token' =>
$accessToken, 'auth' => true]);
}
public function check(){
$check= auth()->check();
return response(['user' => $check]);
}
Here is my AdminController which trows 401 error when executing index method
//as I understood after login I can protect my api with middleware line for example 10 minutes, but unsuccessfully
public function __construct()
{
$this->middleware('auth:api');
}
public function index(){
return response(['foto' => 'testing protection']);
}
here is my react component axios request which initiated 401 error
axios.get("/api/admin/index", {
headers : {
'Content-Type' : 'application/json',
'Accept' : 'application/json',
'Authorization' : 'Bearer' + cookie.get('access_token')
}})
.then(function (response) {
alert(response.data.foto);
})
.catch(function (response) {
alert("bad")
})
//I tried
// headers.append('Authorization', 'bearer ' + cookie.get('access_token'));
// headers.append('Authentication', 'bearer ' + cookie.get('access_token'));
// headers.append('Authorization', 'JWT ' + cookie.get('access_token'));
// headers.append('Authorization', cookie.get('access_token'));
// but error persists
I just want to protect my api with middleware(auth:api)
also auth->check() gives me false, whic is not good I think
So I found my mistake, instead of using
headers : {
'Authorization' : 'Bearer' + cookie.get('access_token')
}
I had to use
//added space
headers : {
'Authorization' : 'Bearer ' + cookie.get('access_token')
}
but the strange thing I had to do in order this to work is add upcoming lines in Kernel middleware:
\App\Http\Middleware\EncryptCookies::class,
\Illuminate\Session\Middleware\StartSession::class
I just tried to use postman instead of axios and got error that something is wrong with sessions and since then it was easy to find needed part

CORS error while sending request from Browser to play server even after sending CORS header

I have a REST API developed using Play Framework/Java and front end developed in Angular JS.
I am trying to call a POST method fron the Angular Client to the server using the following code:
$scope.login = function () {
console.log('login called');
var loginURL = 'http://localhost:9000/login';
var loginInfo = {
'email': $scope.email,
'password': $scope.password
};
$http({
url: loginURL,
method: 'POST',
data: loginInfo,
headers: { 'Content-Type': 'application/json' }
}).then(function (response) {
console.log('SUCCESS: ' + JSON.stringify(response));
$scope.greeting = response.status;
}, function (response) {
console.log('ERROR: ' + JSON.stringify(response));
});
}
This is the code at my server:
public Result doLogin() {
ObjectNode result = Json.newObject();
result.put("status", "success");
return ok(result).withHeader("Access-Control-Allow-Origin", "*");
}
And this is the application conf file:
#allow all hosts.
play.filter.hosts {
allowed = ["."]
}
#allow CORS requests.
play.filters.cors {
allowedOrigins = ["*"]
}
Yet even after enabling CORS, I am getting error in console in both Firefox and Google Chrome:
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://localhost:9000/login. (Reason: CORS header ‘Access-Control-Allow-Origin’ missing).
ERROR: {"data":null,"status":-1,"config":{"method":"POST","transformRequest":[null],"transformResponse":[null],"jsonpCallbackParam":"callback","url":"http://localhost:9000/login","data":{"email":"xxx","password":"xxx"},"headers":{"Content-Type":"application/json","Accept":"application/json, text/plain, /"}},"statusText":""}
I do know that the server is sending the correct response and the correct header because when I do the POST from Postman, I can see the response and also the headers containing {"Access-Control-Allow-Origin", "*"} in Postman.
So then, what could be the problem? Is there something I am missing from the Client side?
The difference between POSTMAN request and browser request is browser sends an OPTIONS request before the actual POST / GET request.
To be able to accept OPTION request with your play framework allowedHttpMethods = ["GET", "POST" ,"OPTIONS"]
for follow this link
Play Framework 2.3 - CORS Headers
This causes a problem accessing CORS request from a framework (like angularjs). It becomes difficult or the framework to find what was the options request for and take action properly.
For fixing your problem you will need to analyze how the options request going and how it's being interpreted and how to overcome. But in general, I suggest using "fetch" built-in request for this, which supports the promises so can be chained easily with angularjs code
so your code will look something like this
$scope.login = function () {
console.log('login called');
var loginURL = 'http://localhost:9000/login';
var loginInfo = {
'email': $scope.email,
'password': $scope.password
};
fetch(loginURL, {
method: 'post',
headers: {
"Content-type": "application/json"
},
body: loginInfo
}).then(function (response) {
console.log('SUCCESS: ' + JSON.stringify(response));
$scope.greeting = response.status;
}, function (response) {
console.log('ERROR: ' + JSON.stringify(response));
});
}

Angularjs Access-Control-Allow-Origin

I have Angularjs app connects to a server using API, and i'm using token authentication, when i use Postman to get the token, it works perfect, but when i'm use Angulajs with the same header and parameters i got error:400.
When i checked both requests using Fiddler, i found that the request from Angularjs is missing Access-Control-Allow-Origin: * header.
How to fix this?
Here is the service used to get the token:
AuthenticationApi.Login = function (loginData) {
//POST's Object
var data = "grant_type=password&username=" + loginData.userName + "&password=" + loginData.password;
var deferred = $q.defer();
//the data will be sent the data as string not JSON object.
$http.post('http://localhost:53194/Token', data, { headers: { 'Content-Type': 'application/x-www-form-urlencoded' } })
.then(function (response) {
console.log(response);
localStorageService.set('authorizationData',
{
token: response.access_token,
userName: loginData.userName
});
Authentication.isAuth = true;
Authentication.userName = loginData.userName;
console.log(Authentication);
deferred.resolve(response);
},
function (err, status) {
logout();
deferred.reject(err);
});
return deferred.promise;
};
for the API server, i'v done CORS:
public void Configuration(IAppBuilder app)
{
ConfigureOAuth(app);
HttpConfiguration config = new HttpConfiguration();
WebApiConfig.Register(config);
app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);
app.UseWebApi(config);
}
i found the problem and i fixed it.
in the API server, i have this code:
var cors = new EnableCorsAttribute("*", "*", "*");
cors.PreflightMaxAge = 60;
config.EnableCors(cors);
The problem is in the PreflightMaxAge, i just commented it...It worked!!!
if the problem not solved, try to use IE or FireFox, don't use Chrome because it is not CORS enabled

Resources