Skip to main content

API Authentication

Introduction

Along with user authentication for the browser, Voltis also provides you with API Authentication and implements this in a very simple and secure manner. As user authentication uses the SessionProtector, Voltis uses the TokenProtector for API authentication.

The token driver is responsible for inspecting the API token sent with a request to a protected API route and will validate the request and allow further execution if the API token is deemed valid and has not expired, it will match this data within the database against a user.

Defining API Routes

For protected API routes, you must define all your API endpoints inside the api.php routes file at app/routing/api.php. In there you can define new API only routes and by default a route group is already setup to use the Voltis Authentication System and the API protector. When you send API requests you need to send a valid client ID and API token to pass authentication.

If your application uses API routes which don’t require authentication, you can just define these routes outside the default provided route group inside api.php.

Protecting API Routes

As mentioned earlier a routing group is already setup for you and it uses the Voltis authentication service and API tokens to validate API endpoints that you define within the group.

Route::group(['prefix' => '/api', 'middleware' => 'Auth:api'], function()
{
// ...
});

A prefix is also defined within the API group as well but you may change this if you like. The authentication middleware is passed the api parameter which relates to your configured protectors in config\auth.php. By default the Auth Middleware does not require a parameter as the default setup is to use the session protector but for an API, we need to define that we want to use the api protector which uses the token driver to authenticate your API requests, you can see this configuration inside auth.php.

The Auth Middleware is defined for you already inside config\middleware.php as \App\Middleware\Authenticate::class which extends Voltis\Auth\Middleware\Authenticate.

API Authentication Outcomes

After you have assigned the Auth:api Middleware to one of your API endpoints, you can perform certain actions based on when a user is unauthorized or authorized by using the App level Middleware located at: app/Http/Middleware/AuthenticateMiddleware.php, which contains two methods for interacting with API authentication:

public function unauthorized()
{
return response([
'error' => [
'status' => 401,
'message' => 'Authorization failed'
]
], 401);
}

public function authorized()
{
// ...
}

Using the unauthorized method, you can perform actions when an API request is deemed invalid due to either the client ID or API token being incorrect. By default a 401 Unauthorized response is sent back with a JSON body, giving an error code and message.

The second method, authorized, allows you to perform actions when a user is deemed valid and their client ID and API token has passed authentication, most of the time you probably don’t need to do anything here, so the default is to do nothing but you are free to use this method how you like.

Database Consideration

For API authentication, the table name must be called api_tokens and contain the following columns and data types:

  • id varchar(36)
  • token_hashed varchar(128)
  • user_id int(11)
  • token_last_active datetime
  • token_expires_at datetime

You may change the api_tokens table name by altering the configuration for api_database_token_table in your auth.php configuration file.

Configuration

All API configuration options can be found within config\auth.php. You can find the options for how the API protector is setup, where the token driver is set and a few API related settings, which all have detailed comments to explain what they do.

Generating Tokens

After you have your api_tokens table setup and configured, you are now ready to start using the provided methods to generate API tokens for your users. Voltis provides you with a method called generateApiToken which will render an API token along with a client ID. When calling this method, after generating the token and client ID it will by default save this to the database but return the clientId, token and hash as an array so you can process this further if you wish. The token returned is the raw API token but the token stored in api_tokens is a sha512 signed hash, using the encryption key you have in your env file.

If you want to only generate API tokens and not have them automatically stored in api_tokens you can pass false to the generateApiToken method like so:

use Voltis\Auth\AuthManager;

$this->auth->generateApiToken($saveToDatabase = true, $userId = null);

As you can see from the example above we can also pass in a custom user ID to generate a API token for a specific user, by default if the user ID is not defined, Voltis will use the ID from the current authenticated user. The token created is generated using PHPs cryptographically secure method random_bytes and the token is returned using bin2hex at 160 characters, stored in the database as a hashed sha512 value.

A collision check will be performed to make sure of the unlikely event where a Client ID already exists. When you generate API tokens, the array returned gives you the chance to show the raw API token to your users, you only really want to show this once for security reasons as the stored token is hashed.

The client ID that gets generated will look something like d9c73454-f693-ce6b-45bc-400e8e80dca5 and is used so you are able to create more than one API token per user, giving you the ability to generate tokens per device etc. The client ID is not generally something you need to keep secure but is probably best to keep safe, the actual API token is what is used for final authentication and is what needs to be kept a secret.

To make it easy to generate API tokens for refreshing them, you can use the refreshApiToken method which will return the hashed value of the new token and the plain-text token for you to display to the user as a refreshed token. The new hashed value is updated in the database but the client ID will stay the same, the token expiration time is also updated.

use Voltis\Auth\AuthManager;

$token = $this->auth->refreshApiToken($clientId);

If you only want to generate a unique client ID and not create or save an actual API token, you are free to call the internal method used to create client IDs which is called generateApiClientId.

You may also quickly generate API tokens only by calling the generateApiTokenOnly method.

info

Voltis gives you the easy ability to generate secure API tokens and as they are stored as a hashed value, you will need to use the provided methods to generate tokens but also implement an API token management interface for your users and web frontend for your application. When tokens are created you should store the hashed value and show the plain-text token to the user for them to keep and as a one-time display.

Revoking API Tokens

Removing a token

To revoke an API token using the actual raw un-hashed token itself, you may use:

use Voltis\Auth\AuthManager;

$this->auth->revokeApiToken($token);

Removing a token by Client ID

To revoke an API token by using the client ID, you may use:

use Voltis\Auth\AuthManager;

$this->auth->revokeApiTokenUsingClientId($clientId);

Removing all tokens by the user ID

To revoke all API tokens for a user, based on the user ID, you may use:

use Voltis\Auth\AuthManager;

// Use the current authenticated user ID to remove all tokens
$this->auth->revokeAllApiTokens($userId = null);

Token Expiration

When you generate new API tokens for a user they are assigned a token lifetime, by default this lifetime is 1 year, giving the token a long life, meaning the user does not have to keep creating new tokens frequently. You may change this lifetime by changing api_token_lifetime located at config\auth.php. Whenever you generate a new token with generateApiToken or refresh a token with refreshApiToken, they will use the configured token lifetime value to create the token_expires_at value that gets stored inside api_tokens.

Along with the token_expires_at, Voltis will automatically update the token_last_active every time it successfully authenticates, allowing you to track when API tokens were last used.

If the token lifetime expires then Voltis will treat any requests sent with an expired lifetime as invalid and not allow the request to process any further. Either a user needs to create a new token, refresh their token or you can extend the expiration using the extendApiTokenLifetime method and pass over how much you want to add to the lifetime of the token, for example:

use Voltis\Auth\AuthManager;

$this->auth->extendApiTokenLifetime($clientId, '+1 month');

Using the Client ID & API Token

Voltis supports a number of ways that you can attach the client ID and API token to your requests, the client ID allows Voltis to figure out which API token and user to validate against and the API token from your request is validated against the hash stored in the database. Let’s take a look at how we can provide these credentials during a request...

Query Parameters

When sending a GET request to your API you may include the client ID and API token as query strings within your URL:

$url = "https://example/api/user/books?client_id=$clientId&api_token=$token";

Request Body

When dealing with POST, PUT, PATCH or DELETE API requests you can use the request body to send the client ID and API token.

JSON Example:

{
"client_id": $clientId,
"api_token": $token
}

The request body can be either form parameters or JSON data. Make sure you set the correct content type header of either application/json or application/x-www-form-urlencoded.

Headers & Bearer Token

A Voltis API application can perform API authentication through the use of Bearer API tokens, all you need to do is pass the client ID and the token using HTTP headers:

ClientID: <your-client-id>
Authorization: Bearer <your-api-token>

These headers are case sensitive and the API token requires the Bearer authentication type to be in front of the token.

While you may use headers to fully interact with your API, you can mix and match how you provide the client ID and token, for example, you could pass the client ID inside the request body and the API token as a header etc. But remember this mixing must respect the request verb types.