Jwt-auth: MethodNotAllowed

Created on 19 Jan 2017  路  5Comments  路  Source: tymondesigns/jwt-auth

Hello, I'm having troubles when I'm trying to use the 'auth:api' middleware in my routes.
With this configuration, the response to the request is 'MethodNotAllowedHttpException in RouteCollection.php'
If I don't use the middleware, it works. Where's the problem?
I'm using "tymon/jwt-auth": "1.0.*@dev"
This is my jwt.php
`

/*

  • This file is part of jwt-auth.
    *
  • (c) Sean Tymon tymon148@gmail.com
    *
  • For the full copyright and license information, please view the LICENSE
  • file that was distributed with this source code.
    */

return [

/*
|--------------------------------------------------------------------------
| JWT Authentication Secret
|--------------------------------------------------------------------------
|
| Don't forget to set this, as it will be used to sign your tokens.
| A helper command is provided for this: `php artisan jwt:generate`
|
*/

'secret' => env('JWT_SECRET', 'tpXoQwcVKlsdCMfcIbufWVcV4eQvlgJg'),

/*
|--------------------------------------------------------------------------
| JWT time to live
|--------------------------------------------------------------------------
|
| Specify the length of time (in minutes) that the token will be valid for.
| Defaults to 1 hour
|
*/

'ttl' => 60,

/*
|--------------------------------------------------------------------------
| Refresh time to live
|--------------------------------------------------------------------------
|
| Specify the length of time (in minutes) that the token can be refreshed
| within. I.E. The user can refresh their token within a 2 week window of
| the original token being created until they must re-authenticate.
| Defaults to 2 weeks
|
*/

'refresh_ttl' => 20160,

/*
|--------------------------------------------------------------------------
| JWT hashing algorithm
|--------------------------------------------------------------------------
|
| Specify the hashing algorithm that will be used to sign the token.
|
| See here: https://github.com/namshi/jose/tree/2.2.0/src/Namshi/JOSE/Signer
| for possible values
|
*/

'algo' => 'HS256',

/*
|--------------------------------------------------------------------------
| User Model namespace
|--------------------------------------------------------------------------
|
| Specify the full namespace to your User model.
| e.g. 'Acme\Entities\User'
|
*/

'user' => 'App\User',

/*
|--------------------------------------------------------------------------
| User identifier
|--------------------------------------------------------------------------
|
| Specify a unique property of the user that will be added as the 'sub'
| claim of the token payload.
|
*/

'identifier' => 'id',

/*
|--------------------------------------------------------------------------
| Required Claims
|--------------------------------------------------------------------------
|
| Specify the required claims that must exist in any token.
| A TokenInvalidException will be thrown if any of these claims are not
| present in the payload.
|
*/

'required_claims' => ['iss', 'iat', 'exp', 'nbf', 'sub', 'jti'],

/*
|--------------------------------------------------------------------------
| Blacklist Enabled
|--------------------------------------------------------------------------
|
| In order to invalidate tokens, you must have the the blacklist enabled.
| If you do not want or need this functionality, then set this to false.
|
*/

'blacklist_enabled' => env('JWT_BLACKLIST_ENABLED', true),

/*
|--------------------------------------------------------------------------
| Providers
|--------------------------------------------------------------------------
|
| Specify the various providers used throughout the package.
|
*/

'providers' => [

    /*
    |--------------------------------------------------------------------------
    | User Provider
    |--------------------------------------------------------------------------
    |
    | Specify the provider that is used to find the user based
    | on the subject claim
    |
    */

    'user' => 'Tymon\JWTAuth\Providers\User\EloquentUserAdapter',

    /*
    |--------------------------------------------------------------------------
    | JWT Provider
    |--------------------------------------------------------------------------
    |
    | Specify the provider that is used to create and decode the tokens.
    |
    */

    'jwt' => Tymon\JWTAuth\Providers\JWT\Namshi::class,

    /*
    |--------------------------------------------------------------------------
    | Authentication Provider
    |--------------------------------------------------------------------------
    |
    | Specify the provider that is used to authenticate users.
    |
    */

    'auth' => Tymon\JWTAuth\Providers\Auth\Illuminate::class,

    /*
    |--------------------------------------------------------------------------
    | Storage Provider
    |--------------------------------------------------------------------------
    |
    | Specify the provider that is used to store tokens in the blacklist
    |
    */

    'storage' => Tymon\JWTAuth\Providers\Storage\Illuminate::class,

],

];`

This is my 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 = [
\Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode::class,
\Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode::class,
\App\Http\Middleware\EncryptCookies::class,
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
\Illuminate\Session\Middleware\StartSession::class,
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
\App\Http\Middleware\Cors::class,
\App\Http\Middleware\VerifyCsrfToken::class,
\Barryvdh\Cors\HandleCors::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\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' => \Illuminate\Auth\Middleware\Authenticate::class,
    'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
    'bindings' => \Illuminate\Routing\Middleware\SubstituteBindings::class,
    'can' => \Illuminate\Auth\Middleware\Authorize::class,
    'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
    'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,

];

}
This is my api.php

use Illuminate\Http\Request;

/*
|--------------------------------------------------------------------------
| API Routes
|--------------------------------------------------------------------------
|
| Here is where you can register API routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| is assigned the "api" middleware group. Enjoy building your API!
|
*/

Route::get('/user', function (Request $request) {
return $request->user();
})->middleware('auth:api');

Route::group(['middleware' => 'auth:api'], function(){
Route::post('/authenticate', 'AuthController@authenticate');
});
Route::get('/', 'IndexController@getIndex');
Route::post('/login', 'LoginController@loginAction');
Route::post('/register', 'UserController@register');
Route::post('/uploadFiles', 'UserController@uploadFiles');
`

And finally this is my auth.php
`

return [

/*
|--------------------------------------------------------------------------
| Authentication Defaults
|--------------------------------------------------------------------------
|
| This option controls the default authentication "guard" and password
| reset options for your application. You may change these defaults
| as required, but they're a perfect start for most applications.
|
*/

'defaults' => [
    'guard' => 'api',
    'passwords' => 'users',
],

/*
|--------------------------------------------------------------------------
| Authentication Guards
|--------------------------------------------------------------------------
|
| Next, you may define every authentication guard for your application.
| Of course, a great default configuration has been defined for you
| here which uses session storage and the Eloquent user provider.
|
| All authentication drivers have a user provider. This defines how the
| users are actually retrieved out of your database or other storage
| mechanisms used by this application to persist your user's data.
|
| Supported: "session", "token"
|
*/

'guards' => [
    'web' => [
        'driver' => 'session',
        'provider' => 'users',
    ],

    'api' => [
        'driver' => 'jwt',
        'provider' => 'users',
    ],
],

/*
|--------------------------------------------------------------------------
| User Providers
|--------------------------------------------------------------------------
|
| All authentication drivers have a user provider. This defines how the
| users are actually retrieved out of your database or other storage
| mechanisms used by this application to persist your user's data.
|
| If you have multiple user tables or models you may configure multiple
| sources which represent each model / table. These sources may then
| be assigned to any extra authentication guards you have defined.
|
| Supported: "database", "eloquent"
|
*/

'providers' => [
    'users' => [
        'driver' => 'eloquent',
        'model' => App\User::class,
    ],

    // 'users' => [
    //     'driver' => 'database',
    //     'table' => 'users',
    // ],
],

/*
|--------------------------------------------------------------------------
| Resetting Passwords
|--------------------------------------------------------------------------
|
| You may specify multiple password reset configurations if you have more
| than one user table or model in the application and you want to have
| separate password reset settings based on the specific user types.
|
| The expire time is the number of minutes that the reset token should be
| considered valid. This security feature keeps tokens short-lived so
| they have less time to be guessed. You may change this as needed.
|
*/

'passwords' => [
    'users' => [
        'provider' => 'users',
        'table' => 'password_resets',
        'expire' => 60,
    ],
],

];
`

stale

Most helpful comment

Again I have the same issue that when I make a request without a token, I get MethodNotAllowedException.

I made some research, It seem that the method that parse the token send a JWTException when it failed to catch a response. JWTException is extends from Exception class and thus not showed to user because it seem laravel only show HttpException.

In the parseToken method JWT.php, if you change the JWTException to DomainException and remove authorization header, It will show the proper error "The token could not be parsed from the request" in the response.

However, I don't know if it is the expected behaviour, and I found myself another solution :

You can set the Accept header to application/json, it will return you a 401 unauthorized error that is more appropriate :

{ "message": "Unauthenticated." }

I will search further to understand where the MethodNotAllowedHttpException come from.

All 5 comments

MethodNowAllowed usually means you are sending a GET request to a POST route or vice versa

Same here.

When a pass a valid token everithing is ok. But when a pass a invalid or expired token, MethodNotAllowedHttpException is throw.

    "require": {
        "php": ">=7.1.3",
        "doctrine/dbal": "^2.6",
        "fideloper/proxy": "~4.0",
        "laravel/framework": "5.6.*",
        "laravel/tinker": "~1.0",
        "tymon/jwt-auth": "1.0.0-rc.2"
    },

Again I have the same issue that when I make a request without a token, I get MethodNotAllowedException.

I made some research, It seem that the method that parse the token send a JWTException when it failed to catch a response. JWTException is extends from Exception class and thus not showed to user because it seem laravel only show HttpException.

In the parseToken method JWT.php, if you change the JWTException to DomainException and remove authorization header, It will show the proper error "The token could not be parsed from the request" in the response.

However, I don't know if it is the expected behaviour, and I found myself another solution :

You can set the Accept header to application/json, it will return you a 401 unauthorized error that is more appropriate :

{ "message": "Unauthenticated." }

I will search further to understand where the MethodNotAllowedHttpException come from.

for 2.0.1 is same bug, only @mhlsf comment true

Is this still relevant? If so, what is blocking it? Is there anything you can do to help move it forward?

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

mihailo-misic picture mihailo-misic  路  3Comments

harveyslash picture harveyslash  路  3Comments

shah-newaz picture shah-newaz  路  3Comments

lloy0076 picture lloy0076  路  3Comments

phamduong picture phamduong  路  3Comments