Laravel API

Sample Project

Download a sample project specific to this tutorial configured with your Auth0 API Keys.

System Requirements
  • Composer 1.5
  • PHP 7.0
  • Laravel 5.5
  • laravel-auth0 5.0.2
Show requirements

At some point, your APIs may need to allow limited access to users, servers, or servers on behalf of users. This tutorial demonstrates how to use the OAuth 2.0 authorization features of Auth0 to give your applications (or third-party applications) limited access to your APIs on behalf of users. For more information, check out our documentation.

Create a Resource Server (API)

In the APIs section of the Auth0 Dashboard, click the Create API button. Provide a Name and Identifier for your API. The identifier you set will later be used as the audience when configuring access_token verification. Be sure to choose the RS256 signing algorithm.

Create API

Add API Authorization

To restrict access to the resources served by your API, a check needs to be made to determine whether the incoming request contains valid authorization information. There are various methods for including authorization information in a request, but for integration with Auth0, your API needs to check for a valid JSON Web Token (JWT). When users log into your application, they will receive an id_token and an access_token which are both JWTs. The specific JWT that needs to be sent to your API is the access_token.

Install the Dependencies

Protecting your Laravel API requires a middleware which will check for and verify an access_token in the Authorization header of an incoming HTTP request. You can use the middleware provided in the laravel-auth0 package.

Install laravel-auth0 using Composer.

Composer is a tool for dependency management in PHP. It allows you to declare the dependent libraries your project needs and it will install them in your project for you. See Composer's getting started doc for information on how to use it.

composer require auth0/login:"~5.0"

Enable the Provider

The laravel-auth0 package comes with a provder called LoginServiceProvider. Add this to the list of application providers.

// config/app.php
'providers' => array(
    // ...
    \Auth0\Login\LoginServiceProvider::class,
);

If you would like to use the Auth0 facade, add it to the list of aliases.

// config/app.php

'aliases' => array(
    // ...
    'Auth0' => \Auth0\Login\Facade\Auth0::class,
);

You will now be able to access user info with Auth0::getUser().

Finally, you need to bind a class that provides a user (your app model user) each time the user is logged in or an access_token is decoded. You can use the Auth0UserRepository provided by this package or you can build your own class.

To use Auth0UserRepository, add the following lines to your AppServiceProvider:

// app/Providers/AppServiceProvider.php

public function register()
{

    $this->app->bind(
        \Auth0\Login\Contract\Auth0UserRepository::class, 
        \Auth0\Login\Repository\Auth0UserRepository::class
    );

}

Configure the Plugin

The laravel-auth0 plugin comes with a configuration file that can be generated using artisan. Generate the file and complete the details found within.

php artisan vendor:publish

After the file is generated, it will be located at config/laravel-auth0.php.

Configure Apache

By default, Apache doesn't parse Authorization headers from incoming HTTP requests. To enable this, add a mod_rewrite to your .htaccess file.

RewriteCond %{HTTP:Authorization} ^(.*)
RewriteRule .* - [e=HTTP_AUTHORIZATION:%1]

Define a User and User Provider

The Laravel authentication system needs a User Object given by a User Provider. With these two abstractions, the user entity can have any structure you like and can be stored anywhere. You configure the User Provider indirectly by selecting a user provider in app/config/auth.php. The default provider is Eloquent, which persists the User model in a database using the ORM.

The laravel-auth0 plugin comes with an authentication driver called auth0. This driver defines a user structure that wraps the normalized user profile defined by Auth0. It doesn't actually persist the object but rather simply stores it in the session for future calls.

This is adequate for basic testing or if you don't have a requirement to persist the user. At any point you can call Auth::check() to determine if there is a user logged in and Auth::user() to retreive the wrapper with the user information.

Configure the driver in /config/auth.php to use auth0.

// app/config/auth.php

// ...
'providers' => [
    'users' => [
        'driver' => 'auth0'
    ],
],

Protect the API Routes

Protecting individual API endpoints can be done by applying the auth:api middleware to them.

// routes/api.php

Route::get('/private', function (Request $request) {
    return response()->json(["message" => "Hello from a private endpoint! You need to have a valid access token to see this."]);
})->middleware('auth:api');

This route is now only accessible if an access_token is included in the Authorization header of the incoming request.

Make Calls to the API

With the laravel-auth0 plugin configured and the auth:api middleware applied to a route, you can now run the application and make calls to it.

Use artisan to serve the application.

php artisan serve

Next send a request to your protected endpoint which includes an access_token.

curl --request GET \
  --url http://localhost:8000/api/private \
  --header 'authorization: Bearer <ACCESS TOKEN>'

Extend the Auth0UserRepository Class

There may be situations where you need to customize the Auth0UserRepository class. For example, you may want to use the default User model and store the user profile in your database. If you need a more advanced custom solution such as this, you can extend the Auth0UserRepository class with your own custom class.

This is an example, the custom class in this scenario will not work unless a database setup has been configured.

// app/Repository/MyCustomUserRepository.php

namespace App\Repository;

use Auth0\Login\Contract\Auth0UserRepository;

class MyCustomUserRepository implements Auth0UserRepository {

    /* This class is used on api authN to fetch the user based on the jwt.*/
    public function getUserByDecodedJWT($jwt) {
      /*
       * The `sub` claim in the token represents the subject of the token
       * and it is always the `user_id`
       */
      $jwt->user_id = $jwt->sub;

      return $this->upsertUser($jwt);
    }

    public function getUserByUserInfo($userInfo) {
      return $this->upsertUser($userInfo['profile']);
    }

    protected function upsertUser($profile) {

      // Note: Requires configured database access
      $user = User::where("auth0id", $profile->user_id)->first();

      if ($user === null) {
          // If not, create one
          $user = new User();
          $user->email = $profile->email; // you should ask for the email scope
          $user->auth0id = $profile->user_id;
          $user->name = $profile->name; // you should ask for the name scope
          $user->save();
      }

      return $user;
    }

    public function getUserByIdentifier($identifier) {
        //Get the user info of the user logged in (probably in session)
        $user = \App::make('auth0')->getUser();

        if ($user === null) return null;

        // build the user
        $user = $this->getUserByUserInfo($user);

        // it is not the same user as logged in, it is not valid
        if ($user && $user->auth0id == $identifier) {
            return $auth0User;
        }
    }

}

With your custom class in place, change the binding in the AppServiceProvider.

// app/Providers/AppServiceProvider.php

// ...
public function register()
{

    $this->app->bind(
        \Auth0\Login\Contract\Auth0UserRepository::class, 
        \App\Repository\MyCustomUserRepository::class 
    );

}

Optional Steps

Configure CORS

To configure CORS, you should add the laravel-cors dependency. You can check it out here.

After installation, add the following to the configuration file for CORS:

'defaults' => array(
    'supportsCredentials' => false,
    'allowedOrigins' => array(),
    'allowedHeaders' => array(),
    'allowedMethods' => array(),
    'exposedHeaders' => array(),
    'maxAge' => 0,
    'hosts' => array(),
),

'paths' => array(
    '*' => array(
        'allowedOrigins' => array('*'),
        'allowedHeaders' => array('Content-Type', 'Authorization', 'Accept'),
        'allowedMethods' => array('POST', 'PUT', 'GET', 'DELETE')
    ),
),
Use Auth0 for FREECreate free Account