I am working on a project with a React front-end and a Laravel back-end. I am trying to set up my authentication system. I am utilizing SPA authentication using Sanctum. I am successfully utilizing the sanctum/csrf-cookie route, where the XSRF-Token cookie is given. When I then try to follow that up with a login, I get a 419 error, CSRF token mismatch. There is no XSRF-Token. What is interesting is that if I do a get request, as in the 'testing' route below, the XSRF cookie is present. However, when I do a post request, as in posting to the login route, the cookie is not present and I get a 419 error.
I am running this locally right now. The front-end is running at localhost:3000, with the back-end running at localhost:8888. Here are various relevant segments of code.
LoginForm.js
let data = {
email: e.target[0].value,
password: e.target[1].value
}
axios.get('http://localhost:8888/sanctum/csrf-cookie')
.then((res) => {
axios.post('http://localhost:8888/login', data)
.then((res) => {
axios.get('http://localhost:8888/user')
})
})
Kernel.php
protected $middleware = [
\App\Http\Middleware\TrustProxies::class,
\Fruitcake\Cors\HandleCors::class,
\App\Http\Middleware\PreventRequestsDuringMaintenance::class,
\Illuminate\Foundation\Http\Middleware\ValidatePostSize::class,
\App\Http\Middleware\TrimStrings::class,
\Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class,
\Illuminate\Session\Middleware\StartSession::class,
\Illuminate\Session\Middleware\AuthenticateSession::class,
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
];
protected $middlewareGroups = [
'web' => [
\App\Http\Middleware\EncryptCookies::class,
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
\App\Http\Middleware\VerifyCsrfToken::class,
\Illuminate\Routing\Middleware\SubstituteBindings::class,
\App\Http\Middleware\HandleInertiaRequests::class,
],
'api' => [
\Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class,
'throttle:api',
\Illuminate\Routing\Middleware\SubstituteBindings::class,
],
];
protected $routeMiddleware = [
'auth' => \App\Http\Middleware\Authenticate::class,
'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
'cache.headers' => \Illuminate\Http\Middleware\SetCacheHeaders::class,
'can' => \Illuminate\Auth\Middleware\Authorize::class,
'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
'password.confirm' => \Illuminate\Auth\Middleware\RequirePassword::class,
'signed' => \Illuminate\Routing\Middleware\ValidateSignature::class,
'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
'verified' => \Illuminate\Auth\Middleware\EnsureEmailIsVerified::class,
];
.env
SESSION_DRIVER=cookie
CLIENT_URL=http://localhost:3000
SESSION_DOMAIN=localhost
SANCTUM_STATEFUL_DOMAINS=http://localhost:3000
Bootstrap.js
axios = require('axios');
axios.defaults.headers.common['Accept'] = 'application/json';
axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';
axios.defaults.withCredentials = true;
Web.php
Route::get('/testing', function () {
return "Testing.";
});
Route::post('/login', function(Request $request) {
$credentials = $request->validate([
'email' => ['required', 'email'],
'password' => ['required'],
]);
if (Auth::attempt($credentials)) {
$request->session()->regenerate();
$id = Auth::id();
$user = User::find($id);
return $user;
}
return back()->withErrors([
'email' => 'The provided credentials do not match our records.',
]);
});
Sanctum.php
'stateful' => explode(',', env('SANCTUM_STATEFUL_DOMAINS', sprintf(
'%s%s',
'localhost,localhost:3000,localhost:8888,
Sanctum::currentApplicationUrlWithPort()
))),
Cors.php
'paths' => [
'api/*',
'sanctum/csrf-cookie',
'login',
'logout',
'register',
'user/password',
'forgot-password',
'reset-password',
'user/profile-information',
'email/verification-notification',
'testing',
'user',
'checkAuth'
],
'allowed_methods' => ['*'],
'allowed_origins' => [env('CLIENT_URL')],
'allowed_origins_patterns' => [],
'allowed_headers' => ['*'],
'exposed_headers' => [],
'max_age' => 0,
'supports_credentials' => true,
Let's review one by one what is needed to apply SPA authentication using sanctum.
First, they must share same top-level domains, however each could be hosted on subdomains, on you case you are using localhost, so this should be fine.
Next, you should configure which domains your SPA will be making requests from. SANCTUM_STATEFUL_DOMAINS. If you are accessing your application via a URL that includes a port (127.0.0.1:8000), you should ensure that you include the port number with the domain. Here, it seems you are missing the port.
Next, you should add middleware as mentioned in https://laravel.com/docs/9.x/sanctum#sanctum-middleware which seems you have already done it.
Next fix cors issue: First, you need to set supports_credentials to be true on config/cors.php. Next, you should enable the withCredentials option on your application's global axios instance. axios.defaults.withCredentials = true;
Finally, you should ensure your application's session cookie domain configuration supports any subdomain of your root domain. SESSION_DOMAIN, looks like you have already set localhost here.
Overall, it seems you need to fix to things:
you need to add port if you are accessing it from port.
you need to set supports_credentials to true on config/cors.php
For more detail, you can follow: https://laravel.com/docs/9.x/sanctum#spa-authentication
As per the Laravel Sanctum documentation :
Additionally, you should ensure that you send the Accept: application/json header with your request.
Since we cannot find misconfigurations in your setup, I will recommend adding a custom middleware in your api group that automatically adds the application/json header :
/* app/Http/Middleware/AjaxHeader.php */
namespace App\Http\Middleware;
use Closure;
class AjaxHeader
{
/**
* Handle incoming request
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle($request, Closure $next)
{
$request->headers->add([
'accept' => 'application/json',
]);
return $next($request);
}
}
And add it to your 'api' middlewareGroups :
/* app/Htpp/Kernel.php */
// ...
protected $middlewareGroups = [
// ...
'api' => [
\Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class,
'throttle:api',
\Illuminate\Routing\Middleware\SubstituteBindings::class,
\App\Http\Middleware\AjaxHeader::class,
],
];
// ...
Related
I'm trying to make Fortify with sanctum work with a custom Guard called SPA.
The admins are logging in on the backend with the Web guard.
The users are logging in on a subdomain that will host a VUEJS SPA.
Admin logs in on -> https://test.local:8890/admin/login and is redirected to https://test.local:8890/admin/dashboard that works -> ok
Users log in on https://spa.test.local:8890 (vue app). -> ok works
Vuefile:
import axios from 'axios'
axios.defaults.withCredentials = true;
axios.defaults.baseURL = 'https://test.local:8890'
export default {
name: 'Home',
components: {
HelloWorld
},
data: () => {
return {
email : 'doe#example.com',
password : 'Password1!'
}
},
methods : {
login() {
axios.get('/sanctum/csrf-cookie').then(response => {
console.log(response.code);
axios.post('web-api/login', {
email : this.email,
password : this.password
}).then(response => {
console.log(response);
}
).catch(error => {
console.log(error);
})
});
}}}
So the idea is that users can not log in on the dashboard and have a separate table
When i log in on my admin i go to the dashboard. I open a new tab in chrome and log in as the user on the subdomain in the vue app. When i go back to the dashboard i'm still logged in so good and i'm logged in on the other tab as the user (super)
But when inspecting the cookies in chrome https://test.local:8890/ and https://spa.test.local:8890/ share the same cookie laravel_session and xcsrf token... they are identical...
So now when i go to admins tab and go to the web-api route https://test.local:8890/web-api/user i see the user's credentials :
{"id":4,"first_name":"Happy","last_name":"Doe","email":"doe#example.com"}
Yet i can still visit my dashboard as Admin.
config/auth.php
'defaults' => [
'guard' => 'web',
'passwords' => 'admins',
],
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'admins', //admin provider for web
],
'spa' => [
'driver' => 'session',
'provider' => 'users' //user provicer for spa (and api)
],
/*'api' => [
'driver' => 'token',
'provider' => 'users',
'hash' => false, //user provider
],*/
],
I've added guard parameter to sanctum config.
config/sanctum:
'guard' => 'spa', //set sanctum guard to spa.
In the Kernel file i've copied everything from the 'web' middleware to 'spa' because it works almost the same.
Kernel.php:
protected $middlewareGroups = [
'web' => [
\App\Http\Middleware\EncryptCookies::class,
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
\Illuminate\Session\Middleware\StartSession::class,
// \Illuminate\Session\Middleware\AuthenticateSession::class,
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
\App\Http\Middleware\VerifyCsrfToken::class,
\Illuminate\Routing\Middleware\SubstituteBindings::class,
],
'spa' => [
\App\Http\Middleware\EncryptCookies::class,
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
\Illuminate\Session\Middleware\StartSession::class,
\App\Http\Middleware\VerifyCsrfToken::class,
\Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class,
'throttle:api',
\Illuminate\Routing\Middleware\SubstituteBindings::class
],
'api' => [
'throttle:api',
\Illuminate\Routing\Middleware\SubstituteBindings::class,
],
];
Configured Sanctum parameters in the env file.
.env :
SESSION_DOMAIN=test.local
SANCTUM_STATEFUL_DOMAINS=.test.local
Added the SPA to routeServiceProvider boot method
RouteServiceProvider.php:
public function boot()
{
$this->configureRateLimiting();
$this->routes(function () {
Route::prefix('web-api')
->middleware('spa')
->namespace($this->namespace)
->group(base_path('routes/spa.php'));
/*Route::prefix('api')
->middleware('api')
->namespace($this->namespace)
->group(base_path('routes/api.php'));*/
Route::middleware('web')
->namespace($this->namespace)
->group(base_path('routes/web.php'));
});
}
Then my login function in SpaAuthController: (as used by the spa)
public function loginSpa(Request $request){
//Regenerate session
$request->session()->regenerate();
$request->validate([
'email' => 'required|email',
'password' => 'required',
]);
$authAttempt = Auth::guard('spa')->attempt(['email' => $request->email, 'password' => $request->password]);
if($authAttempt){
$user = Auth::guard('spa')->user();
if (!$user->hasVerifiedEmail()){
abort(401, 'Email address not verified.');
}
if ($user->blocked){
abort(401, 'Your Account blocked.');
}
return response([],204);
}
return response(['message' => 'The provided credentials are incorrect.'],422);
}
The entire web login is handled by default fortify controllers...
POST | admin/login | | Laravel\Fortify\Http\Controllers\AuthenticatedSessionController#store | web
At this point it's getting kinda funny, what am i doing wrong here and should i be worried for potential security issue presume yes :D)
I cannot get my Laravel setup to find my authenticated user in my StripeController. I am trying to set up a Stripe webhook to perform an action once a successful payment has been made.
I have done lots of reading on similar issues but after trying fixes I've read, most of them contiue to return null.
My latest attempt is below which returns status code 419 and Page Expired.
StripeController.php
class StripeController extends Controller
{
public function __construct(){
\Stripe\Stripe::setApiKey(env('STRIPE_SECRET'));
}
public function paymentSuccess()
{
// The commented code fetches the first User OK but I want the logged in user.
// $userDetails = User::first();
// $userDetails->is_subscribed = 1;
// $userDetails->save();
//This always returns null, as does any other user() command.
return Auth::user();
}
public function createSession(Request $request)
{
$session = \Stripe\Checkout\Session::create([
"success_url" => "https://www.mymarketingwizard.io/#/dashboard",
"cancel_url" => "https://example.com/cancel",
"payment_method_types" => ["card"],
"line_items" => [[
"name" => "Lifetime Access",
"description" => "Lifetime Access",
"amount" => 15000,
"currency" => "gbp",
"quantity" => 1
]]
]);
return $session;
}
My login script:
AuthController.php
public function login(Request $request)
{
$request->validate([
'email' => 'required|string|email',
'password' => 'required|string'
]);
$credentials = request(['email', 'password']);
$credentials['active'] = 1;
$credentials['deleted_at'] = null;
if(!Auth::attempt($credentials))
return response()->json(['error' => 'unauthorized'],404);
$user = $request->user();
$tokenResult = $user->createToken('Personal Access Token');
$token = $tokenResult->token;
if ($request->remember_me)
$token->expires_at = Carbon::now()->addWeeks(1);
$token->save();
return response()->json([
'access_token' => $tokenResult->accessToken,
'token_type' => 'Bearer',
'expires_at' => Carbon::parse(
$tokenResult->token->expires_at
)->toDateTimeString()
]);
}
I have read lots of other similar questions about this issue, many pointing towards a 'middleware' => 'web' must be used where you want to access Auth::user so this is my latest attempt:
api.php
Route::group(['prefix' => '/'], function () {
Route::group(['middleware' => 'web'], function () {
Route::auth();
Route::post('paymentSuccess','StripeController#paymentSuccess'); // Route I'm a hitting via Stripe
});
Route::post('login', 'AuthController#login');
Route::post('send-token', 'AuthController#sendToken');
Route::post('validate-token', 'AuthController#validateToken');
Route::post('reset-password', 'AuthController#resetPassword');
Route::group(['middleware' => 'auth:api'], function() {
Route::post('session','StripeController#createSession');
I have also read other solutions about moving the 'web' classes out of middlewareGroups and into global middleware in the Kernel.php but that also did't work for me.
Kernel.php
namespace App\Http;
use Illuminate\Foundation\Http\Kernel as HttpKernel;
class Kernel extends HttpKernel
{
/**
* The application's global HTTP middleware stack.
*
* These middleware are run during every request to your application.
*
* #var array
*/
protected $middleware = [
\App\Http\Middleware\CheckForMaintenanceMode::class,
\Illuminate\Foundation\Http\Middleware\ValidatePostSize::class,
\App\Http\Middleware\TrimStrings::class,
\Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class,
\App\Http\Middleware\TrustProxies::class,
\Spatie\Cors\Cors::class,
];
/**
* The application's route middleware groups.
*
* #var array
*/
protected $middlewareGroups = [
'web' => [
\App\Http\Middleware\EncryptCookies::class,
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
\Illuminate\Session\Middleware\StartSession::class,
\Illuminate\Session\Middleware\AuthenticateSession::class,
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
\App\Http\Middleware\VerifyCsrfToken::class,
\Illuminate\Routing\Middleware\SubstituteBindings::class,
],
'api' => [
'throttle:60,1',
'bindings',
],
];
/**
* The application's route middleware.
*
* These middleware may be assigned to groups or used individually.
*
* #var array
*/
protected $routeMiddleware = [
'auth' => \App\Http\Middleware\Authenticate::class,
'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
'bindings' => \Illuminate\Routing\Middleware\SubstituteBindings::class,
'cache.headers' => \Illuminate\Http\Middleware\SetCacheHeaders::class,
'can' => \Illuminate\Auth\Middleware\Authorize::class,
'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
'signed' => \Illuminate\Routing\Middleware\ValidateSignature::class,
'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
'verified' => \Illuminate\Auth\Middleware\EnsureEmailIsVerified::class,
];
/**
* The priority-sorted list of middleware.
*
* This forces non-global middleware to always be in the given order.
*
* #var array
*/
protected $middlewarePriority = [
\Illuminate\Session\Middleware\StartSession::class,
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
\App\Http\Middleware\Authenticate::class,
\Illuminate\Session\Middleware\AuthenticateSession::class,
\Illuminate\Routing\Middleware\SubstituteBindings::class,
\Illuminate\Auth\Middleware\Authorize::class,
];
}
Payment.vue
This is my Vue Component which creates the Stripe session when the component is first created. When the user clicks the proceed to checkout button, the method is executed.
methods: {
checkout() {
stripe
.redirectToCheckout({
sessionId: this.sessionId.id
})
.then(result => {
// If `redirectToCheckout` fails due to a browser or network
// error, display the localized error message to your customer
// using `result.error.message`.
})
}
},
created() {
api
.post('/session')
.then(response => {
this.sessionId = response.data
})
.catch(error => {
})
}
My goal is to update my Users' table to say that the user who processed the payment is now subscribed.
This usually happens when CSRF check failed. Add your webhook endpoint as an exception in VerifyCsrfToken middleware:
protected $except = [
'paymentSuccess',
];
Just getting started with barryvdh/laravel-cors. I have a server side application running on port 8000 which authenticates users via Laravel Passport, and my react.js client application running on port 3000. Right now I'm trying to get a "login" action working.
From the client when I provide correct credentials a token is sent back and the status is 200. When the credentials are invalid a 401 is returned. So good so far. However, if I provide only an email in the form and no password I get the following CORS related error:
When the error is thrown, the following network calls occur:
My login on the client side:
login = (email, password) => {
console.log(email);
fetch("http://localhost:8000/api/auth/login", {
method: 'POST',
body: JSON.stringify({
'email': email,
'password': password
}),
headers: {
'Content-Type': 'application/json'
}
})
.then(res => res.json())
.then(response => {
console.log(response['access_token']); //with correct credentials this is logged out and set in local storage
localStorage.setItem('access_token', response['access_token']);
})
.catch(error => console.error('Error: ', error));
}
Server side:
public function login(Request $request)
{
$request->validate([
'email' => 'required|string|email',
'password' => 'required|string',
'remember_me' => 'boolean'
]);
$credentials = request(['email', 'password']);
if(!Auth::attempt($credentials)) {
return response()->json([
'message' => 'Unauthorized'
], 401);
}
$user = $request->user();
$tokenResult = $user->createToken('Personal Access Token');
$token = $tokenResult->token;
if ($request->remember_me) {
$token->expires_at = Carbon::now()->addWeeks(1);
}
$token->save();
return response()->json([
'access_token' => $tokenResult->accessToken,
'token_type' => 'Bearer',
'expires_at' => Carbon::parse(
$tokenResult->token->expires_at
)->toDateTimeString()
]);
}
cors.php (published from barryvdh/laravel-cors package):
return [
'supportsCredentials' => false,
'allowedOrigins' => ['*'],
'allowedOriginsPatterns' => [],
'allowedHeaders' => ['*'],
'allowedMethods' => ['*'],
'exposedHeaders' => [],
'maxAge' => 0,
];
api.php:
Route::group(['prefix' => 'auth',], function () {
Route::post('login', 'AuthController#login');
Route::post('register', 'AuthController#register');
Route::get('register/activate/{token}', 'AuthController#registerActivate');
Route::group(['middleware' => 'auth:api'], function() {
Route::get('logout', 'AuthController#logout');
Route::get('user', 'AuthController#user');
});
});
Kernel.php:
protected $middlewareGroups = [
'web' => [
\App\Http\Middleware\EncryptCookies::class,
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
\Illuminate\Session\Middleware\StartSession::class,
// \Illuminate\Session\Middleware\AuthenticateSession::class,
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
\App\Http\Middleware\VerifyCsrfToken::class,
\Illuminate\Routing\Middleware\SubstituteBindings::class,
],
'api' => [
\Barryvdh\Cors\HandleCors::class,
'throttle:60,1',
'bindings',
],
];
protected $middleware = [
\Barryvdh\Cors\HandleCors::class,
\App\Http\Middleware\CheckForMaintenanceMode::class,
\Illuminate\Foundation\Http\Middleware\ValidatePostSize::class,
\App\Http\Middleware\TrimStrings::class,
\Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class,
\App\Http\Middleware\TrustProxies::class
];
Making the same POST request (one to /api/auth/login with the password excluded) via postman I get the expected error message:
{
"message": "The given data was invalid.",
"errors": {
"password": [
"The password field is required."
]
}
}
But, making this through the react client application the error in the screenshot is thrown. I'm guessing this has something to do with the preflight HTTP OPTIONS request that the browser sends out as part of how CORS works.
How can I correct this? I'd expect a 401 to be returned for the status and for the react client to get the same JSON message that Postman receives in the case that the password is empty. It just seems weird that based on the payload for that POST request, a CORS related error occurs. Does this mean that the server and/or client is not setting up CORS correctly?
It seems that the error is thrown when an error occurs in your backend.
As mentioned in the docs :
When an error occurs, the middleware isn't run completely. So when
this happens, you won't see the actual result, but will get a CORS
error instead.
This issue helped figuring the source of the error
First of all the class member:
protected $middleware
Will apply the middleware for both api and web
From laravel.com/docs/5.8/middleware#registering-middleware
If you want a middleware to run during every HTTP request to your application, list the middleware class in the $middleware property of your app/Http/Kernel.php class.
See also: barryvdh/laravel-cors#global-usage
So try to register your middleware one time by removing:
\Barryvdh\Cors\HandleCors::class of your 'api' middleware group.
And for logical purposes refactor your protected $middleware with:
protected $middleware = [
\App\Http\Middleware\CheckForMaintenanceMode::class,
\Illuminate\Foundation\Http\Middleware\ValidatePostSize::class,
\App\Http\Middleware\TrimStrings::class,
\Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class,
\App\Http\Middleware\TrustProxies::class,
\Barryvdh\Cors\HandleCors::class,
];
I'm trying to create an API with Bearer Token but I can't figure it out:
What does the route::middleware('auth:api') do
Where's the code of route::middleware('auth:api')
So, I have the following code in my Routes\Api.php file:
Route::get('/login', function (Request $request)
{
if(Auth::guard()->attempt(['email' => $request->email, 'password' => $request->password]) == FALSE)
return response()->json(['status' => FALSE]);
$user = Users::select('id', 'name', 'api_token', 'created_at')->where('email', $request->email)->firstOrFail();
return response()->json(['status' => TRUE, 'user' => $user]);
});
Route::middleware('auth:api')->get('/bookings', function (Request $request)
{
return response()->json(['its working!']);
});
I'm able to successfully connect to the route /login and retrieve the api_token. Now this token must be used in the /bookings route in order to authenticate.
I was hopping the middleware('auth:api')verify my CURL headers for the Authorization: Bearer zzzzzzzzz, but its not working.
So basically I need to understand how do I change the code logic behind auth:api or if I should create a new middleware and check for the request headers?
Diclamer
If you need custom code to handle authentication you should create your own middleware and authentication guard and use it instead of the default one that Laravel provides.
Your questions
What does the route::middleware('auth:api') do
It states that the route should implement the middleware "auth" and the middleware group "api".
Where's the code of route::middleware('auth:api')
All middleware in Laravel is defined in app/Http/Kernel.php.
In there you will probably see something like
protected $middlewareGroups = [
....,
'api' => [
'throttle:60,1',
'bindings',
],
];
and
protected $routeMiddleware = [
...,
'auth' => \Illuminate\Auth\Middleware\Authenticate::class,
'bindings' => \Illuminate\Routing\Middleware\SubstituteBindings::class,
'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
];
This means that a route using the middleware auth:api implements the api middleware group (in this case the ThrottleRequests and SubstituteBinding middleware) and the auth middleware (Authenticate).
The actual authentication guard used depends on the configuration in your auth.php config file:
'guards' => [
'api' => [
'driver' => 'token',
'provider' => 'users',
],
],
In the case above a TokenGuard is used (laravel/framework/src/Illuminate/Auth/TokenGuard.php).
So to answer your question, the code for the auth middleware can be found at
laravel/framework/src/Illuminate/Auth/Middleware/Authenticate.php
Using postman on localhost, I'm able to use POST successfully on my API. But when deployed to a server and using postman, I always get the error 405:MethodNotAllowedHttpException, even though the POST request is stated for the route, took our verifycsrf from middleware, and took out the web middleware. Also followed the CORS installation for laravel project by barryvdh.
Wondering if anyone has any suggestions to fix this?
Kernel:
namespace App\Http;
use Illuminate\Foundation\Http\Kernel as HttpKernel;
class Kernel extends HttpKernel
{
/**
* The application's global HTTP middleware stack.
*
* These middleware are run during every request to your application.
*
* #var array
*/
protected $middleware = [
\Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode::class,
\Illuminate\Session\Middleware\StartSession::class,
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
'Barryvdh\Cors\HandleCors',
];
/**
* The application's route middleware groups.
*
* #var array
*/
protected $middlewareGroups = [
'web' => [
\App\Http\Middleware\EncryptCookies::class,
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
\App\Http\Middleware\VerifyCsrfToken::class,
],
'api' => [
'throttle:60,1',
],
'admin' => [
\App\Http\Middleware\EncryptCookies::class,
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
\App\Http\Middleware\VerifyCsrfToken::class,
\App\Http\Middleware\PermissionAdminMiddleware::class,
],
];
/**
* The application's route middleware.
*
* These middleware may be assigned to groups or used individually.
*
* #var array
*/
protected $routeMiddleware = [
'auth' => \App\Http\Middleware\Authenticate::class,
'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
];
}
cors.php
return [
/*
|--------------------------------------------------------------------------
| Laravel CORS
|--------------------------------------------------------------------------
|
| allowedOrigins, allowedHeaders and allowedMethods can be set to array('*')
| to accept any value.
|
*/
'supportsCredentials' => false,
'allowedOrigins' => ['*'],
'allowedHeaders' => ['*'],
'allowedMethods' => ['*'],
'exposedHeaders' => [],
'maxAge' => 5,
'hosts' => [],
];
app.php includes Barryvdh\Cors\ServiceProvider::class,
routes.php
Route::group(
[
'prefix' => 'api',
'middleware' => ['cors']
],
function()
{
Route::post('dummy', 'API\UsersController#dummy');
}
);
UsersController.php
namespace App\Http\Controllers\API;
use App\Http\Controllers\FP\UserController;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
use Illuminate\Database\Eloquent\ModelNotFoundException;
class UsersController extends Controller
{
function dummy(Request $request){
return "test";
}
}
Add Accept header in postman to application/json.