Laravel 5.4 / Angular possible mishandled rejection due to cross origin request blocked - angularjs

I am currently building an application using token based authentication with Angular and Laravel. I initially set things up just to test the API by creating a BookController . At first I was getting a Cross Origin Request Block error when I tried to call this data from Angular. However I managed to resolve this by adding the headers to my routes/web.php file. Here is the whole file. NB: After adding these headers I was succesfully able to use the API even from another domain
<?php
header('Access-Control-Allow-Origin: *');
header( 'Access-Control-Allow-Headers: Authorization, Content-Type' );
//Route::get('/', 'BookController#show');
//Route::resource('book/create', 'BookController#create');
Auth::routes();
Route::get('/', 'HomeController#index');
Route::resource('book', 'BookController');
Route::resource('authenticate', 'AuthenticateController', ['only' => ['index']]);
Route::post('authenticate', 'AuthenticateController#authenticate');
However I am currently following this tutorial to set up token based authentication. https://scotch.io/tutorials/token-based-authentication-for-angularjs-and-laravel-apps
To summarise , my issue is when I submit the form containing username and password I am getting the following errors. Below I will try elaborate a bit more but it is quite difficult as there is alot to it.
Cross-Origin Request Blocked: The Same Origin Policy disallows reading
the remote resource at http://www.example.local/authenticate/.
(Reason: CORS header 'Access-Control-Allow-Origin' missing).
And
Possibly unhandled rejection:
{"data":null,"status":-1,"config":{"method":"POST","transformRequest":[null],"transformResponse":[null],"jsonpCallbackParam":"callback","url":"http://www.example.local/authenticate/","data":{"email":"dasdas#Dasa.com","password":"fsdfd"},"withCredentials":false,"headers":{"Accept":"application/json,
text/plain,
/","Content-Type":"application/json;charset=utf-8"}},"statusText":""}
I am using Angular UI Router V 0.4.2 and satellizer. My Angular version is 1.6.2 It using a different domain than the API. Much like the working example above.
On the laravel side I also followed this tutorial to add middleware to attempt to resolve this but no luck.
http://en.vedovelli.com.br/2015/web-development/Laravel-5-1-enable-CORS/
I will also include my AuthenticateController.php file..
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Http\Requests;
use App\Http\Controllers\Controller;
use JWTAuth;
use Tymon\JWTAuth\Exceptions\JWTException;
use App\User;
class AuthenticateController extends Controller
{
public function __construct()
{
// Apply the jwt.auth middleware to all methods in this controller
// except for the authenticate method. We don't want to prevent
// the user from retrieving their token if they don't already have it
$this->middleware('jwt.auth', ['except' => ['authenticate']]);
$this->middleware('cors');
}
public function index()
{
// Retrieve all the users in the database and return them
$users = User::all();
return $users;
}
public function authenticate(Request $request)
{
$credentials = $request->only('email', 'password');
try {
// verify the credentials and create a token for the user
if (! $token = JWTAuth::attempt($credentials)) {
return response()->json(['error' => 'invalid_credentials'], 401);
}
} catch (JWTException $e) {
// something went wrong
return response()->json(['error' => 'could_not_create_token'], 500);
}
// if no errors are encountered we can return a JWT
return response()->json(compact('token'));
}
}
My issue is I do not even know if the "possibly unhandled rejection" is related to the "Cross-Origin Request Blocked" error. But I have to assume it is.
Can you recognise anything from my routes files that may be allowing one and not another?
EDIT:
I have noticed the difference between one request and another is that one is a GET request while another is an OPTIONS request. This may be the cause.
I have since added Header set Access-Control-Allow-Origin "*" to both the virtual hosts config file in Apache and to a .htaccess file in the root of the Laravel project. Still no change.
I am wondering is this related something in Angular

Your server code needs to handle that OPTIONS request by sending a headers-only response to it that includes the Access-Control-Allow-Methods: GET, POST, PUT, DELETE header and Access-Control-Allow-Headers: Authorization, Content-Type header.
Or you can just try using https://github.com/barryvdh/laravel-cors which makes all this easier.
https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS#Preflighted_requests has general info you might want to read up on.

Related

404 Not Found error in preflight OPTIONS when executing a PUT method in CakePHP API with axios in React App

So, we have an API with CakePHP 3.7. We are using resources to generate CRUD methods. The API is hosted in a server with apache2 and is accessed through a manager app using React (this app is a microservice). The manager makes the calls through axios and is correctly managing the GET, POST and HEAD requests (simple CORS requests) but we're having problems when it comes to more complex requests such as PUT or DELETE.
When executing PUT or DELETE requests it makes a preflight OPTIONS request and it returns a 404 Not Found error. And some messages in console related with CORS which are:
https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS/Errors/CORSPreflightDidNotSucceed?utm_source=devtools&utm_medium=firefox-cors-errors&utm_campaign=default
https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS/Errors/CORSDidNotSucceed?utm_source=devtools&utm_medium=firefox-cors-errors&utm_campaign=default
We already tried several fixes, such as using CakePHP CORS plugin, adding CORS Headers in the response in the beforeRender and beforeFilter methods of AppController and also adding CORS headers in the apache, none of this seams to be working.
private function setCorsHeaders() {
$this->response->cors($this->request)
->allowOrigin(['*'])
->allowMethods(['*'])
->exposeHeaders(['X-Total-Pages'])
->maxAge(800)
->build();
}
public function beforeRender(Event $event)
{
$this->setCorsHeaders();
}
public function beforeFilter(Event $event)
{
if($this->request->is('options')) {
$this->setCorsHeaders();
return $this->response;
}
}
Header set Access-Control-Expose-Headers "X-Total-Pages"
Header set Access-Control-Allow-Origin "*"
Header set Access-Control-Allow-Methods "GET,HEAD,PUT,PATCH,POST,DELETE,OPTIONS"
The expected behaviour is that the PUT and DELETE methods are executed properly (the preflight OPTIONS should pass successfully). Any help is apreciated.
In CakePHP >=3.4, Http\Response objects are treated as immutable by many methods. The method chain called on $this->request->cors() uses the CorsBuilder class to queue the desired headers on an immutable response which is returned when calling build().
Try assigning the return from CorsBuilder::build() with the queued headers to $this->response.
private function setCorsHeaders() {
$this->response = $this->response->cors($this->request)
->allowOrigin(['*'])
->allowMethods(['*'])
->exposeHeaders(['X-Total-Pages'])
->maxAge(800)
->build();
}

Setting a header in CakePHP (MVC)

I'm trying to integrate PayPal's IPN code into CakePHP 3.
namespace App\Controller;
use PayPal\Api\PaypalIPN;
class IpnController extends AppController
{
public function index()
{
$this->autoRender = false;
$ipn = new PayPalIPN();
// Use the sandbox endpoint during testing.
$ipn->useSandbox();
$verified = $ipn->verifyIPN();
if ($verified) {
/*
* Process IPN
* A list of variables is available here:
* https://developer.paypal.com/webapps/developer/docs/classic/ipn/integration-guide/IPNandPDTVariables/
*/
}
// Reply with an empty 200 response to indicate to paypal the IPN was received correctly.
header("HTTP/1.1 200 OK");
}
}
This is failing to validate on PayPal's end and I'm suspecting it has to do with setting the headers in the controller view.
Is there a way to set the header properly in CakePHP's controller.
I had this code running stand alone (in just a php file) and it seemed to work just fine.
You should not output any data in your controller action - that means you should not use echo, header() or any function or construct that would return anything to browser. If you do, you will encounter a "headers already sent" error.
If you want to set headers, you should use withHeader() or withAddedHeader() methods of Cake\Http\Response.
For status codes, you also have withStatus() method:
$response = $this->response;
$response = $response->withStatus(200,"OK");
return $response; // returning response will stop controller from rendering a view.
More about setting headers can be found in docs:
Setting response headers in CakePHP 3
Cake\Http\Response::withStatus()
Maybe that's not very Cakish, but actually one can send headers this way - it just have to be followed by die; or exit; to prevent app from further response processing.
Anyway, for sure your problem is not associated with headers. IPN seems to doesn't work properly with Paypal Sandbox. Maybe you should try it other way with ApiContext class?

ionic laravel XMLHttpRequest cannot load

i am new to this and i am trying to login and get a token so the ionic and laravel can communicate. I am using satellizer and jwt on laravel. on post man i get the token back:
this is what i am getting loging in from ionic:
[enter image description here][2]
the error says:
XMLHttpRequest cannot load http://localhost:8000/api/authenticate. Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:8100' is therefore not allowed access.
and yeah, on my laravel side, i have included
header("Access-Control-Allow-Origin: *");
what am i missing here, thank you
There are many factors to why this happens. the error may happen because you have no access headers and the browsers gets this and blocks your requests.
It also happens when you your server experiences internal errors like 500,403,401 etc. you may have added headers to the requests life cycle(like in the middleware to filter all api requests) in your laravel app but sometimes an error 500 or even an echo or dd() interrupts the whole request life cycle and returns the errors WHICH the browser can't interpret through an ajax call and therefore it loses the headers you implicitly added thus the browser goes back to the preflight request error..
The only solution I suggest is proper error handling in your code and returning errors in a response and return it in json format.
public function someController extends Controller{
public function Foo(Request $request){
$input_bag = [
'some input' => first_$input,
'another important input' => $second_input,
];
$i = 0;
foreach ($input_bag as $key => $value) {
$value = trim($value);
if (empty($value)) {
$error_bag[$i] = "$key empty";
$i++;
} else {
//
}
}
//filter of false or null values
if (array_filter($error_bag)) {
return response()->json($error_bag, 400);
}
}
this returns a json response of the errors while running the code. and good use of try catches and returning the appropriate responses could make your debugging life easy.

Unknown Reason for JWT Tokens invalidation

I'm facing very weird problem with my laravel-Angular application. I'm using Tymon JWT to refresh token on my every request. I'm using Satellizer library to handle these JWT-Tokens, however, Satellizer doesn't seem to have a response interceptor to capture the new token. Hence I wrote my own Interceptor to do so.
.factory('ResponseHttpInterceptor', function ($window) {
return {
response: function (response) {
if (response.headers('Authorization') != null) {
$window.localStorage.removeItem('satellizer_token');
$window.localStorage.setItem('satellizer_token', response.headers('Authorization').replace('Bearer ', ''));
}
return response;
}
}
})
This code basically captures the new token and replaces the existing token in local storage with the new token.
My test flow is:
Login -> Make who Am I call -> Logout
Upon Logout I receive an error Invalid token (this doesn't happen always. Sometimes the flow succeeds and sometimes it fails). This flow works perfect via REST Client postman. So I don't think there is any problem in my API's
Attaching image showing the new token being passed, after it is refreshed after my whoami call.
Upon logout I'm clearing the local storage. Can Anyone tell me what could be the reason for this?
EDIT
Route::group(['prefix' => 'api/v1_0'], function () {
Route::post('login', 'Auth\AuthControllerGeneral#postLogin');
Route::get('logout', ['middleware' => 'jwt.auth', 'uses' => 'Auth\AuthControllerGeneral#getLogout']);
Route::group(['middleware' => ['jwt.refresh', 'jwt.auth']], function() {
Route::get('whoami', 'Auth\AuthControllerGeneral#loggedInUserInfo');
});
});
Check you htaccess you should have below code there
RewriteEngine On
RewriteCond %{HTTP:Authorization} ^(.*)
RewriteRule .* - [e=HTTP_AUTHORIZATION:%1]
And AuthContrller is same as https://github.com/sahat/satellizer/blob/master/examples/server/php/app/Http/Controllers/AuthController.php
And Some people forget to check Authenticate middleware. Check this also
https://github.com/sahat/satellizer/blob/master/examples/server/php/app/Http/Middleware/Authenticate.php
I suggest first try with default route as in demo
https://github.com/sahat/satellizer/blob/master/examples/server/php/app/Http/routes.php
And still you not get the solution then try with sample client end folder.
https://github.com/sahat/satellizer/tree/master/examples/client
Which you can put in your laravel public folder just to test.
I found everything working fine in satellizer but some people fails in configuring this.

Cross-Origin Request Blocked - Laravel

i have try to access(get request) my laravel api from ionic(angularjs) app.
but it keep getting bellow error.
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://128.xxx.xxx.xx/mobi/check/?username=achchu&apikey=1N7GyYRfq8bQnrFCCGgL
please help me to fix this
This response is based on the fact that it appears you have control of serve-side code.
Have you added CORS support to the response? If you have not done so it could be like this.
You could add a handler thus:
Route::head("/<path to resource>", function () {
$r = Response::make("hello");
//Access-Control-Allow-Origin: http://api.bob.com
// Access-Control-Allow-Credentials: true
$r->header("Access-Control-Allow-Origin", "<*|client request domain>")
->("Access-Control-Allow-Credentials", "true")
->("Access-Control-Request-Method", "GET");
});
Perhaps you could set this headers on the response you are sending itself, I'm not sure. If that is possible and you might use this sort of thing on several routes it's better you prepare it as a filter. You can read more on CORS at http://www.html5rocks.com/en/tutorials/cors/ .
If what you want to send is json data think about serving your response to support jsonp. You could do something like:
$normalData = Model::all();
// if the client made a jsonp style request
if (Input::has("callback")) {
$data = "<script>" . Input::get("callback") . "(" . json_encode($normalData) . ")";
return Response::make($data)->header("Content-Type", "appplication/javascript");
}else {
//if not then return normally
return Response::json($normalData);
}
You are trying to access api from one domain to a different domain.
There are many ways to overcome this issue,but since it is a get Request,use **jsonp*.
Try something like this
var url = ' http://128.xxx.xxx.xx/mobi/check/?username=achchu&apikey=1N7GyYRfq8bQnrFCCGgL&callback=JSON_CALLBACK';
$http.jsonp(url)
.success(function(data) {
});

Resources