In project, all API calls are from Lumen. Front is developed in Laravel. We are calling Lumen APIs using Guzzle http client guzzleHttp.
Now, I need to set header Authorization for all API calls so I'm sending token in header from Laravel but in Lumen I can't get token in Lumen request header.
Below is the example code.
Laravel controller code:
public function get_category(){
$accessToken = 'kjdhfdkjfhdkjfhfjkdf9875443213456';
$response = \Guzzle::request("GET","example.com", "categories",['headers' => [
'Authorization' => $accessToken
]]);
$category_all = json_decode($response->getBody()->getContents(),true);
return $category_all;
}
Lumen middleware code:
public function handle($request, Closure $next)
{
dd($request);
}
In Lumen request I can't get token in request header.
If you're using Apache, by default it remove the Authorization header.
You've to add this settings in the .htaccess project's file or in the apache .conf file (usually in /etc/apache2/sites-available/):
RewriteEngine On
RewriteCond %{HTTP:Authorization} ^(.*)
RewriteRule .* - [e=HTTP_AUTHORIZATION:%1]
Header set Access-Control-Allow-Headers "Authorization"
Related
I'm working on an webapp (Laravel/Vue) with a subdomain per organisation (companyone.mydomain.com, companytwo.mydomain.com, ...)
As authentication system I'm using Laravel Sanctum with cookies. While setting a cookie is working on localhost it's not working when using subdomains locally.
My backend is running on localhost:8000 while the frontend is running on localhost:8080. For cors reasons I've added a proxy property in vue.config.js
module.exports = {
devServer: {
disableHostCheck: true,
proxy: 'http://localhost:8000',
},
};
I've changed the /etc/hosts file so I can simulate subdomains locally
127.0.0.1 localhost
127.0.0.1 mydomain.com
127.0.0.1 companyone.mydomain.com
127.0.0.1 companytwo.mydomain.com
On the backend I've added the following lines to the .env file (and restarted the php artisan serve script)
SESSION_DOMAIN=.mydomain.com
SANCTUM_STATEFUL_DOMAINS=mydomain.com
In the Authcontroller I'm returning the cookie like this
$token = $user->createToken(Str::random(10))->plainTextToken;
$cookie = cookie('mydomain_api', $token, 60 * 24);
return response([
'token' => $token,
'user' => new AuthResource($user)
], 200)->withCookie($cookie);
The cookie settings are the following
$domain = null
$secure = true
$httpOnly = true
$sameSite = 'None'
When calling the login function I'm receiving the cookie in my browser like this
but Application -> Cookies stays empty
The request header
When sending another request to the api, no cookies are added.
How can I get the cookie in the Cookies storage?
[EDIT 1] When hardcoding the domain on the backend to mydomain.com I'm getting the following error in the browser
Update your .env
SANCTUM_STATEFUL_DOMAINS=localhost:8080,mydomain.com:8080,companyone.mydomain.com:8080,companytwo.mydomain.com:8080,::1,localhost:8080,localhost:3000
try to add folowing lines in your in .htaccess file
# Handle Authorization Header
# RewriteCond %{HTTP:Authorization} .
# RewriteRule .* - [E=Authorization:%{HTTP:Authorization}]
So I store images inside my public folder inside a subdirectory called 'images', and I'm trying to make a request to one of them.
However, I constantly get the error;
Access to fetch at 'http://project.test/images/4obrUhRprw6CXSHsHEGEf4Gje2baKoiS7PQJvS4F.jpeg' from origin 'http://localhost:8080' has been blocked by CORS policy: 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.
I think this is because I'm using VueJS as an SPA frontend, as if I head to project.test and make the request it works fine.
I'm using laravel-cors but after some research, I've found that apparently doesn't apply to the public folder, so I've tried playing around with the .htaccess file inside of public and this is what I've got;
<IfModule mod_rewrite.c>
<IfModule mod_negotiation.c>
Options -MultiViews -Indexes
</IfModule>
<IfModule mod_headers.c>
SetEnvIf Origin "http(s)?://([^.]+\.)?(localhost:8080)$" AccessControlAllowOrigin=$0$1
Header add Access-Control-Allow-Origin %{AccessControlAllowOrigin}e env=AccessControlAllowOrigin
Header set Access-Control-Allow-Credentials true
</IfModule>
RewriteEngine On
# Handle Authorization Header
RewriteCond %{HTTP:Authorization} .
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
# Redirect Trailing Slashes If Not A Folder...
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} (.+)/$
RewriteRule ^ %1 [L,R=301]
# Handle Front Controller...
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ index.php [L]
</IfModule>
However, it still doesn't appear to work and I get the same error when making a request from my Vue localhost instead of project.test. I should also note I'm using Valet.
Hopefully someone can give some help on this.
I put this line in .htaccess file:
Header always set Access-Control-Allow-Origin "*"
and it worked for me.
I had a similiar problem with following setup:
An enabled CorsMiddleware that worked as it is supposed to do with the different get, post, put etc. routes.
An images folder inside the "public"-folder of the lumen project. Accessing files inside the images folder would lead to an CORS error, although CorsMiddleware worked for routes.
Solution that worked for me:
Based on the suggestion of #Hadeel Mostafa, I added a .htaccess file to the public/images folder with the following line:
Header always set Access-Control-Allow-Origin "*"
Adding the same line to the .htaccess of the public folder on the other hand didn't work. It caused the allow-origin header to be set twice (by CorsMiddleware and .htaccess). So the key in my case, was adding an own .htaccess to the subfolder.
Add middleware with CORS
<?php
namespace App\Http\Middleware;
use Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode as Middleware;
use Closure;
use Illuminate\Support\Facades\Response;
class CORS extends Middleware {
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle($request, Closure $next)
{
$origin = $request->header('origin');
$origin = $origin ?? '*';
// ALLOW OPTIONS METHOD
$headers = [
'Access-Control-Allow-Origin' => $origin,
'Access-Control-Allow-Methods'=> 'GET, POST, DELETE, PUT, OPTIONS, HEAD, PATCH',
'Access-Control-Allow-Headers'=> 'Authorization,DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Set-Cookie',
'Access-Control-Allow-Credentials'=> 'true'
];
if($request->getMethod() == "OPTIONS") {
// The client-side application can set only headers allowed in Access-Control-Allow-Headers
return Response::make('OK', 200, $headers);
}
$response = $next($request);
foreach($headers as $key => $value) {
$response->header($key, $value);
}
return $response;
}
}
File app/Http/Kernel.php
protected $middleware = [
// Your middleware...
\App\Http\Middleware\CORS::class,
];
An easier solution would be to use fruitcake/laravel-cors and edit this line in your cors.php config file:
'paths' => ['api/*', 'sanctum/csrf-cookie'],
to
'paths' => ['api/*', 'sanctum/csrf-cookie', '/images/*'],
Happy coding!
Add these lines at the top of bootstrap\app.php file. Actually, Middlewares only work with routes not in all requests so to allow it for all add code in where the app is bootstraped.
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Methods: *');
header('Access-Control-Allow-Headers: *');
for testing must refresh browser cache or go to incognito mode because browsers get response from the cache.
My project need to run a security test requested by the client.
I use OWASP ZAP to run the test.
and it'll given back cookie No HttpOnly Flag warning, and it happended because of the "X-XSRF TOKEN" cookie didn't set httponly flag.
I did some research, and I know about this cookie didn't set httponly for javascript librarys like axios to use it.
but I use laravel 5.5, and in initial project, there is a great mechanism to let javascript library get this token without operate cookie directly, by meta flag:
......
// layout.blade.php
<!-- CSRF Token -->
<meta name="csrf-token" content="{{ csrf_token() }}">
......
and in index.js:
/**
* Next we will register the CSRF Token as a common header with Axios so that
* all outgoing HTTP requests automatically have it attached. This is just
* a simple convenience so we don't have to attach every token manually.
*/
let token = document.head.querySelector('meta[name="csrf-token"]');
if (token) {
window.axios.defaults.headers.common['X-CSRF-TOKEN'] = token.content;
} else {
console.error('CSRF token not found: https://laravel.com/docs/csrf#csrf-x-csrf-token');
}
so it should be work fine even if XSRF-TOKEN 's httponly flag set to true.
I trace src code, and realize that I can modify just one line to make it work.
and somenoe already open a pr on github to solve this question:
https://github.com/ametad/framework/commit/2241b020ae3001ce5dabc1b7c5ea1514ff7f2e33
but I don't feel free to modify source code of framework,
so I try to modify cookie header via apache server (by public/.httaccess)
# public/.httaccess
<ifModule mod_headers.c>
Header always edit Set-Cookie: (.*) "$1, httponly"
Header set X-Content-Type-Options nosniff
Header always append X-Frame-Options SAMEORIGIN
Header set X-XSS-Protection "1; mode=block"
</ifModule>
but Header always edit Set-Cookie: (.*) "$1, httponly" didn't work for me.
below this line is all work, just set-cookie not work.
any idea how to fix this problem?
Firstly it generally isn't necessary to have the XSRF-TOKEN be http only. This cookie is encrypted (all Laravel cookies get encrypted) therefore even if a client does gain access to it, it does not actually contain any useful information.
You can override the default VerifyCsrfToken middleware with your own:
namespace App\Http\Middleware;
use Closure;
use Illuminate\Foundation\Http\Middleware\VerifyCsrfToken as BaseVerifier;
class VerifyCsrfToken extends BaseVerifier {
protected function addCookieToResponse($request, $response)
{
$config = config('session');
$response->headers->setCookie(
new Cookie(
'XSRF-TOKEN', $request->session()->token(), $this->availableAt(60 * $config['lifetime']),
$config['path'], $config['domain'], $config['secure'], $config['http_only'], false, $config['same_site'] ?? null
)
);
return $response;
}
}
You can then replace the framework VerifyCsrfToken in Http/Kernel.php with your own overrriden one.
The downside to this is when you upgrade your Laravel version you will need to ensure your overriden class will still be compatible with the base class.
I am authenticating users with JWTAuth OctoberCMS API plugin. When I register user or login with postman, the request return a token. However when I try to access authenticated routes like:
Route::get('api/v1/todos',
'Wafush\Maswali\Controllers\Todos#index')->middleware('\Tymon\JWTAuth\Middleware\GetUserFromToken');
I am getting {"error":"token_not_provided"} exception yet the user is authenticated.
Again when I attempt to return signed in user object like:
$user = JWTAuth::authenticate();
return $user;
I get the following error:
A token is required
C:\xampp\htdocs\myapp\plugins\vdomah\jwtauth\vendor\tymon\jwt-auth\src\JWTAuth.php line 299
Type
Undefined
Exception
Tymon\JWTAuth\Exceptions\JWTException
{
if ($token) {
return $this->setToken($token);
} elseif ($this->token) {
return $this;
} else {
throw new JWTException('A token is required', 400);
}
}
/**
* Set the request instance.
*
What I am missing. Kindly guide. Its like the token is not getting set.
I got to your question because I was facing the same problem and I've just solved it by adding below code to my .htaccess
# Authorization header
RewriteCond %{HTTP:Authorization} ^(.*)
RewriteRule .* - [e=HTTP_AUTHORIZATION:%1]
I dont get it. I am struggling with this since hours
I am using Vue.js with Laravel and try to make a POST Request to an external API.
But i am always getting a CORS error on my Vue POST Request
methods: {
chargeCustomer(){
this.$http.post('/api/chargeCustomer', this.payment).then(function (response) {
console.log(response.data)
},function (response) {
console.log(response.data)
});
}
}
ERROR
MLHttpRequest cannot load
https://www.mollie.com/payscreen/select-method/JucpqJQses. No
'Access-Control-Allow-Origin' header is present on the requested
resource. Origin 'https://payment.dev' is therefore not allowed
access.
I installed the Laravel CORS Package for my Backend and added the middleware to my route e.g
Route::group(['middleware' => 'cors'], function(){
Route::post('/api/chargeCustomer', 'Backend\PaymentController#chargeCustomer');
});
But i am still getting the error. I also tried to add the Vue Headers with
Vue.http.headers.common['Access-Control-Allow-Origin'] = '*';
Vue.http.headers.common['Access-Control-Request-Method'] = '*';
With the same result/error.
Could someone tell me what i am doing wrong?
You need to set up the CORS headers from the middleware. Maybe you need some extra setup?
Anyway, you can create your own middleware and set up the CORS headers in the handle() method like the following example:
public function handle($request, Closure $next)
{
return $next($request)
->header('Access-Control-Allow-Origin', 'http://yourfrontenddomain.com') // maybe put this into the .env file so you can change the URL in production.
->header('Access-Control-Allow-Methods', '*') // or specify `'GET, POST, PUT, DELETE'` etc as the second parameter if you want to restrict the methods that are allowed.
->header('Access-Control-Allow-Headers', 'X-Requested-With, Content-Type, Authorization') // or add your headers.
}
Add your custom middleware to the global $middleware array (under CheckForMaintenanceMode::class) in the Kernel.php class and you should be good to go.
Other way (without creating a new laravel middleware) is add these headers at the begining of your routes.php
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Methods: POST, GET, OPTIONS, PUT, DELETE');
header('Access-Control-Allow-Headers: Content-Type, X-Auth-Token, Origin, Authorization');
and add this before your interceptors on vue:
Vue.http.options.crossOrigin = true