Search code examples
laravelaxioslaravel-passport

How to construct a private sever-to-client-side API? Laravel Passport?


I'm not sure if I'm using the correct method for my problem.

I would like to get Infos via Axios. For example: calling: /api/user with Axios gets me the user, but I don't want to see the information when I go on domain.test/api/user.

I even want to use API calls to get Results of Functions even if the User is a Guest.

I installed everything there is on the Laravel Documentation for API, but still I'm not sure how the user gets the Token.

So if I call:

axios.get('/api/user')
    .then(response => {
        console.log(response.data);
    }); 

I get from the network tab {"message":"Unauthenticated."}. (I didn't forget to set: ...Middleware\CreateFreshApiToken::class and everything there is).

I think my problem is that I didn't register the User correctly. I got my two keys what should I do with it?

And then it's weird, reading the blog https://laravelcode.com/post/laravel-passport-create-rest-api-with-authentication, they use

$success['token'] =  $user->createToken('MyApp')->accessToken;

But I don't get it. Where do I save it? I'm super confused, because every blog about shows Laravel Passport completely differently.

Or am I doing it wrong?


Solution

  • Passport is an OAuth2 server implementation which offers several different authorization strategies. While it is certainly possible to use Passport for authentication, it's primary purpose is authorization. This is done via token scopes. The type of token you choose to issue depends on your intended purpose with the API and whom your intended target is to be consuming your api.

    Let's start with the following:

    $success['token'] =  $user->createToken('MyApp')->accessToken;
    

    Here they are creating Personal Access Tokens. This is the simplest means of consuming your api, since clients are able to create the token themselves as needed and are long lived.

    The Password Grant strategy is also a good option. A common approach when using this strategy is proxying authentications to Passport internally and merging the client id and secret into the request in a middleware.

    public function handle($request, $next) {
        return $next(tap($request, function($request) {
            $request->merge([
                 'client_id' => config('services.passport.client.id'),
                 'client_secret' => config('services.passport.client.secret')
            ]);
            // do any other pre-request work needed here 
        }));
    }
    

    Setup

    To get started with Passport, run the command:

    php artisan passport:install
    

    This will create the encryption keys as well as a personal access and password grant client types, which will be stored in your database in the oauth_clients table.

    Guard and Middleware

    API routes need to be using the api guard, done by setting auth:api middleware on the route group(s) or Controller constructor.

    // using via constructor 
    public function __construct()
    {
        $this->middleware('auth:api');
    }
    
    // via a route group
    Route::group(['middleware' => ['auth:api'], function() {
        // your api routes 
    });
    

    Passport Routes

    Your user model needs to be using the trait HasApiTokens and within the AuthServiceProvider call Passport::routes() in the boot method.

    public function boot()
    {
        $this->registerPolicies();
    
        Passport::routes();
    
        // this is also an ideal time to set some token expiration values
        Passport::tokensExpireIn(now()->addDays(15));
        Passport::refreshTokensExpireIn(now()->addDays(30));
    }
    

    To use the personal access token strategy for authentication, you need to create your own login and logout routes instead of using the builtin Laravel auth mechanisms.

    Referring to the tutorial in your question, they have defined the following routes:

    Route::post('login', 'API\PassportController@login');
    Route::post('register', 'API\PassportController@register');
    

    and the login method implemented as:

    public function login(){
        if(Auth::attempt(['email' => request('email'), 'password' => request('password')])){
            $user = Auth::user();
            $success['token'] =  $user->createToken('MyApp')->accessToken;
            return response()->json(['success' => $success], $this->successStatus);
        }
        else{
            return response()->json(['error'=>'Unauthorised'], 401);
        }
    }
    

    This is expecting a ajax request with an email and password to be posted to login and if successful it responds with an access token.

    Storing/Using the Token

    This token must be stored client side, either in a cookie or local storage, for example, and then added to every request from the client there after. You'll add the token to the Authorization header in client requests.

    // Use a response interceptor to check for a token and put it in storage 
    axios.interceptors.response.use(response => {
      // store the token client side (cookie, localStorage, etc)
      if (response.data.token) {
        localStorage.setItem('token', token)
      }
      return response
    }, error => {
      // Do something with response error
      return Promise.reject(error);
    });
    
    // Use a request interceptor to add the Authorization header
    axios.interceptors.request.use(config => {
      // Get the token from storage (cookie, localStorage, etc.)
      token = localStorage.getItem('token')
      config.headers.common['Authorization'] = `Bearer ${token}`
      return config;
    }, error => {
      // Do something with request error
      return Promise.reject(error);
    });
    

    Accessing the Authenticated User

    In order to get the user, pass the 'api' parameter to the auth() helper, Auth facade, or through the request:

    $user = auth('api')->user();
    
    $user = Auth::user('api');
    
    $user = request()->user('api');
    

    Keep in mind personal access tokens are long lived, so it's up to you to decide when and how they should expire.

    Any http client can be used to make api requests, axios is a very common option and included with each Laravel installation.