Search code examples
phplaraveloauth-2.0laravel-passport

Laravel Passport Auth::user()->token return null while Auth::user is not null


I'm trying to output the current user's access token in Laravel. This is my current controller Class PassportController.php

class PassportController extends Controller
{
    public function __construct()
    {
        $this->middleware(function ($request, $next) {
            $this->user = Auth::user();
            if (Auth::user() == null) return response(['message' => 'Unauthenticated']);
            return $next($request);
        });
    } 
    public function getToken()
    {
        $token = Auth::user()->token;
        return response($token);
    }
}

model Users.php

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Foundation\Auth\User as Authenticatable; // use Illuminate\Database\Eloquent\Casts\Attribute; use Laravel\Passport\HasApiTokens; use Illuminate\Notifications\Notifiable;


    class User extends Authenticatable
    {
        use HasFactory, HasApiTokens, Notifiable;
    
        
        protected $fillable = ['username', 'password'];
        public function messages()
        {
            return $this->hasMany(Message::class);
        }
    
        public function rooms()
        {
            return $this->belongsToMany(Room::class, 'room_user', 'user_id', 'room_id');
        }
    
        protected $hidden = ['created_at', 'password', 'updated_at', 'rmb_token'];
    }

Route

  Route::get('/tokens', 'API\PassportController@getToken');

I have also made sure to include the Authorization header in my Postman request with the content as Bearer {access_token}. While Auth::user returns a user like expected when I tried Auth::user()->token it gives me

App\Models\User::token must return a relationship instance

error and when I dd(Auth::user()->token) I got it as null. I have also remembered to put in

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

in config/auth.php so I'm not sure what could be causing this. I'm running the latest version of Laravel(laravel 9.45.0).


Solution

  • Auth::user() - this is a data object containing information about an authorized user, data about which, in turn, is stored in your database in the users table.

    Tokens in this table are not stored and are not stored! If you use passport, then your tokens are stored in the oauth_access_tokens table.

    Therefore, why did you decide that you should contain an authorization token in the Auth::user() object? Of course, unless you somehow write it there through some kind of crutch, modifying the object. But this is fundamentally wrong!

    Your authorization controller should look something like this:

    <?php
    
    namespace App\Controllers\Auth;
    
    use App\Http\Controllers\Controller;
    use Illuminate\Http\JsonResponse;
    use Carbon\Carbon;
    use App\Requests\LoginRequest;
    
    /**
     * Class LoginController
     * @package App\Controllers\Auth
     */
    class LoginController extends Controller
    {
        /**
         * @param LoginRequest $request
         * @return JsonResponse
         */
        public function login (LoginRequest $request): JsonResponse
        {
            $credentials = $request->only('email', 'password');
    
            if (\Auth::attempt($credentials) === false) {
                return response()->json([
                    'status' => false,
                    'errors' => ['message' => __('auth.login_error')],
                    'data'   => []
                ], 403);
            }
    
            $user = $request->user();
            $tokenResult = $user->createToken('YOUR Personal Access Token');
    
            return response()->json([
                'status' => true,
                'errors' => [],
                'data' => [
                    'token_type' => 'Bearer',
                    'token'      => $tokenResult->accessToken,
                    'expires_at' => Carbon::parse($tokenResult->token->expires_at)->toDateTimeString(),
                    'user'       => $user
                ]
            ]);
        }
    }
    

    Request class will look something like this:

    <?php
    
    namespace App\Requests;
    
    use Illuminate\Contracts\Validation\Validator;
    use Illuminate\Foundation\Http\FormRequest;
    use Illuminate\Http\Exceptions\HttpResponseException;
    use Illuminate\Http\JsonResponse;
    use Illuminate\Validation\ValidationException;
    
    /**
     * Class LoginRequest
     * @package App\Requests
     */
    class LoginRequest extends FormRequest
    {
        /**
         * Determine if the user is authorized to make this request.
         *
         * @return bool
         */
        public function authorize(): bool
        {
            return true;
        }
    
        /**
         * Get the validation rules that apply to the request.
         *
         * @return string[]
         */
        public function rules(): array
        {
            return [
                'email' => 'required|string|email|max:100',
                'password' => 'required|string|min:6|max:20',
            ];
        }
    
        /**
         * @param Validator $validator
         */
        protected function failedValidation(Validator $validator)
        {
            // remove the redirect for authorization by api
            $errors = (new ValidationException($validator))->errors();
            throw new HttpResponseException(
                response()->json([
                    'status' => false,
                    'errors' => $errors,
                    'data'   => []
                ], JsonResponse::HTTP_UNPROCESSABLE_ENTITY)
            );
        }
    }