cult3

Adding Oauth to a Laravel API

Aug 17, 2015

Table of contents:

  1. How does Oauth work?
  2. What are “Grants”?
  3. How is a Oauth implemented?
  4. Installing an Oauth package
  5. Implementing the Storage interfaces
  6. Adding the Oauth authentication endpoint
  7. Adding an Oauth middleware
  8. Test hitting an endpoint
  9. Conclusion

When building an API, an important consideration is what type of authentication you should implement.

A popular choice is HTTP Basic authentication because it is very easy to set up an use.

However, HTTP Basic authentication is quite limited in a number of different ways.

Its often a better choice to just bite the bullet and use Oauth 2.0.

Oauth 2.0 is a recognised open standard that defines how authentication should work. The specification defines a number of different “grants” that can be used under different circumstances and it is used by some of the biggest and well known modern online companies.

As I mentioned in last weeks post, when building an API, you should always look to implement and adhere to recognised standards as it will make consuming your API a lot easier.

In today’s tutorial we’re going to be looking at setting up an Oauth 2.0 server as part of a Laravel API.

How does Oauth work?

Oauth is an open standard for authorisation that defines a number of different strategies for authenticating with an API.

One of the most common uses of Oauth is to allow a user to authenticate via a third-party platform without exposing their password to the application. You will see this in action whenever you login via Twitter or Facebook.

Typically this will involve clicking on the “Sign in with Twitter” button, where you will be redirected to Twitter to authenticate and then be redirected back to the original application.

When authentication is approved, the Oauth server will generate an access token that can be used on behalf of the user. This access token must be provided when making subsequent requests to the API.

The access token will expire after a predefined set amount of time and so the API consumer will be required to use a refresh token to continue accessing the API.

The access token can also be granted scopes to allow or restrict access to certain aspects of the API. This is useful when you want the user to be able to control how much access the client has to their account.

What are “Grants”?

An Oauth “Grant” is a strategy for acquiring an access token on behalf of a user. OAuth defines a number of grants for common application use cases.

For example, when creating your own applications to access your API, you can use the Password Grant because you trust your own application.

If you are creating an application that will allow third-party developers to build on top of your API, you will want to implement the Authorisation Grant, which allows user’s to sign in to a third-party applications without exposing their password.

Or if you are creating an automated service that needs to connect to your application without requiring authentication as a specific user, you can use the Client Credentials Grant.

How is a Oauth implemented?

OAuth is implemented as two distinct components, the Authorisation Server and the Resource Server.

The Authorisation Server grants access tokens and will accept the initial request from the client.

The Resource Server holds the resources of the API. This will accept the access token and then check with the Authorisation Server whether this request is valid.

The Authorisation Server and the Resource Server can either be two separate applications, or one single application. The Oauth specification does not dictate how these two components should be implemented.

If authentication is something that should be a separate service within your organisation, you might want to keep the Authorisation as a separate application, otherwise it’s probably going to be easier to have the two components within the same application.

Installing an Oauth package

OAuth is a recognised and open standard and so there are a plethora of existing Open Source solutions. Implementing Oauth is not something you want to do yourself as there is really very little value in reinventing the wheel.

Instead I’m going to use the league/oauth2-server package.

To install this package, run the following command in terminal:

composer require league/oauth2-server

Implementing the Storage interfaces

One of the great features of this package is that it is pretty agnostic to how you store your data. Instead of forcing a particular method on you, the package allows you to implement your own storage implementations as long as they adhere to the Interface contracts.

Within a Laravel application you will first need to define the table migrations and then implementations for each of the storage interfaces.

Instead of copying the code into this tutorial I’ll simply link to my files on Github.

You can see my migrations here.

And you can see my storage implementations here.

At some point in the past I copied the majority of this code from an existing package. However, I can’t find that original project to give props to.

Once you have the storage implementations set up you will need to register them in the Laravel IoC container. You can see my Service Provider here.

Note, on this line you will need to actually be authenticating the user, rather than just returning true.

Adding the Oauth authentication endpoint

Next we need to add the endpoint to allow a client to request an access_token using one of the predefined grants. The client will send a POST request to this endpoint so the route definition will look like this:

<?php namespace Cribbb\Http\Routes;

use Illuminate\Contracts\Routing\Registrar;

class OauthRoutes
{
    /**
     * Define the routes
     *
     * @param Registrar $router
     * @return void
     */
    public function map(Registrar $router)
    {
        $router->post("auth/access_token", [
            "as" => "access_token",
            "uses" => "OauthController@accessToken",
        ]);
    }
}

We also need to create an OauthController to deal with this request:

<?php namespace Cribbb\Http\Controllers;

use League\OAuth2\Server\AuthorizationServer;
use League\OAuth2\Server\Exception\OAuthException;

class OauthController extends Controller
{
    /**
     * @var AuthorizationServer
     */
    private $server;

    /**
     * @var AuthorizationServer $server
     * @return void
     */
    public function __construct(AuthorizationServer $server)
    {
        $this->server = $server;
    }

    /**
     * Authenticate via the Access Token Grant
     *
     * @return JsonResponse
     */
    public function accessToken()
    {
        try {
            $response = $this->server->issueAccessToken();

            return response()->json($response);
        } catch (OAuthException $e) {
            $error = $e->errorType;
            $message = $e->getMessage();
            $code = $e->httpStatusCode;
            $headers = $e->getHttpHeaders();

            return response()->json(
                compact("error", "message"),
                $code,
                $headers
            );
        }
    }
}

As you can see, this Controller is fairly simple as all we really need to do is pass the request on to the Authorisation Server component of the Oauth Package.

If the authentication request is successful we can return the response, or if not, we can catch the Exception and return the error response.

Adding an Oauth middleware

After the client has authorised, they must provide the access_token as a header to the request. When our application receives this request, we can grab this token to get the user.

To ensure the routes of the application can only be accessed with an Access Token we can add a Middleware class:

<?php namespace Cribbb\Http\Middleware;

use Closure;
use Illuminate\Http\JsonResponse;
use League\OAuth2\Server\ResourceServer;
use League\OAuth2\Server\Exception\OAuthException;

class Oauth
{
    /**
     * @var ResourceServer
     */
    private $server;

    /**
     * @param ResourceServer $server
     * @return void
     */
    public function __construct(ResourceServer $server)
    {
        $this->server = $server;
    }

    /**
     * Handle an incoming request
     *
     * @param Request $request
     * @param Closure $next
     * @return Response
     */
    public function handle($request, Closure $next)
    {
        try {
            $this->server->isValidRequest();

            return $next($request);
        } catch (OAuthException $e) {
            return new JsonResponse(
                [
                    "error" => $e->errorType,
                    "message" => $e->getMessage(),
                ],
                $e->httpStatusCode,
                $e->getHttpHeaders()
            );
        }
    }
}

This middleware checks to ensure that the request is valid. If the request is valid the request is passed on to the next layer of the application.

If the request is not valid we can catch the Exception and return an appropriate response.

Test hitting an endpoint

We now have everything in place to send a request to the application to retrieve an access_token. A good way of doing this is to use Postman, which is an addon for Chrome. Alternatively, you could always use good old cURL.

Before you do this you will need to ensure you have created a valid user and a method for authenticating that user!

Now you can simply send the POST request, retrieve a token and then use that token to access the endpoints of your API as that authenticated user.

This part of the process really depends on which Oauth grant you set up. If this is your first time at the rodeo I would suggest you get started with the Password Grant.

Conclusion

Oauth can be a bit tricky to get your head around if you have never set it up before.

There’s a lot going on, and there’s a lot of different moving parts to get your head around,

However once you have set up Oauth, there’s really nothing else to do to deal with authentication.

It will also be very easy to add additional grants in the future as your application evolves.

You don’t want to be in the situation where every api consumer use HTTP Basic, but you need to switch to Oauth. It’s better to just do Oauth from the start!

Don’t be overwhelmed by Oauth, it’s really not that difficult once you’ve got the basics working.

Philip Brown

@philipbrown

© Yellow Flag Ltd 2024.