For the examples used in this document, we will assume we're working on a Symfony project. For any information regarding another framework you can refer to its dedicated section. If the section doesn't exist it means that it is not supported yet! Please feel free to contribute.

Required not to break format below

::: info | PSR7 Decoders will expect a PSR7 Request to work, you can use any library to convert Symfony Requests to PSR7 ones. In the following examples we will be using EasyPsr7Factory :::


# Decoding BasicAuth only

To decode BasicAuth only we will register a single decoder for BasicAuth.

# config/packages/easy_api_token.yaml

easy_api_token:
    decoders:
        basic: null

Once the configuration done, we will be able to use the EasyApiTokenDecoderFactoryInterface to build our decoder using its name. The name of a decoder is the key used to register it under decoders in the configuration, so in our case it is basic.

Once the decoder built, we just have to use it to decode the ApiToken for a given request. Let's take the example of controller.

// src/Controller/MyController.php

namespace App\Controller;

use EonX\EasyApiToken\Interfaces\Factories\ApiTokenDecoderFactoryInterface;
use EonX\EasyPsr7Factory\Interfaces\EasyPsr7FactoryInterface;
use Symfony\Component\HttpFoundation\Request;

final class MyController
{
    public function __invoke(
        ApiTokenDecoderFactoryInterface $decoderFactory,
        EasyPsr7FactoryInterface $psr7Factory,
        Request $request
    ){
        $decoder = $decoderFactory->build('basic'); // Use the name of the decoder as an argument

        $psr7Request = $psr7Factory->createRequest($request); // Convert Symfony request to PSR7 request

        $apiToken = $decoder->decode($psr7Request); // Decode token for given PSR7 request

        /**
         * $apiToken will be either a EonX\EasyApiToken\Interfaces\Tokens\BasicAuthEasyApiTokenInterface instance
         * or null if no BasicAuth provided on the given request.
         */

        // Use the $apiToken...
    }
}

# Decoding User ApiKey only

Let's start from the previous example and see how to decode User ApiKey only instead of BasicAuth. First, modify your configuration to add the user-apikey decoder.

# config/packages/easy_api_token.yaml

easy_api_token:
    decoders:
        basic: null # Already there from previous example

        user-apikey: null

Once the configuration updated, simply change the argument given to the decoder factory to be user-apikey and... done!

// src/Controller/MyController.php

namespace App\Controller;

use EonX\EasyApiToken\Interfaces\Factories\ApiTokenDecoderFactoryInterface;
use EonX\EasyPsr7Factory\Interfaces\EasyPsr7FactoryInterface;
use Symfony\Component\HttpFoundation\Request;

final class MyController
{
    public function __invoke(
        ApiTokenDecoderFactoryInterface $decoderFactory,
        EasyPsr7FactoryInterface $psr7Factory,
        Request $request
    ){
        $decoder = $decoderFactory->build('user-apikey'); // Use the name of the decoder as an argument

        $psr7Request = $psr7Factory->createRequest($request); // Convert Symfony request to PSR7 request

        $apiToken = $decoder->decode($psr7Request); // Decode token for given PSR7 request

        /**
         * $apiToken will now be either a EonX\EasyApiToken\Interfaces\Tokens\ApiKeyEasyApiTokenInterface instance
         * or null if no BasicAuth provided on the given request.
         */

        // Use the $apiToken...
    }
}

# Decoding BasicAuth and User ApiKey

We now know how to decode BasicAuth or User ApiKey, good but... How are we supposed to know when to use one or the other?

Here comes the chain decoder, this decoder isn't made to handle any ApiToken strategy but to accept a list of decoders and loop through each of them until an ApiToken is decoded! Let's see how that works.


Modify your configuration to add the chain decoder and set the other decoders into its list option.

# config/packages/easy_api_token.yaml

easy_api_token:
    decoders:
        chain:
            list: # The list option contains a list of other decoders name
                - basic
                - user-apikey

        # Existing decoders
        basic: null
        user-apikey: null

Once the configuration updated, replace the argument for the decoder factory to chain and... Again we're done!

// src/Controller/MyController.php

namespace App\Controller;

use EonX\EasyApiToken\Interfaces\Factories\ApiTokenDecoderFactoryInterface;
use EonX\EasyPsr7Factory\Interfaces\EasyPsr7FactoryInterface;
use Symfony\Component\HttpFoundation\Request;

final class MyController
{
    public function __invoke(
        ApiTokenDecoderFactoryInterface $decoderFactory,
        EasyPsr7FactoryInterface $psr7Factory,
        Request $request
    ){
        $decoder = $decoderFactory->build('chain'); // Use the name of the decoder as an argument

        $psr7Request = $psr7Factory->createRequest($request); // Convert Symfony request to PSR7 request

        $apiToken = $decoder->decode($psr7Request); // Decode token for given PSR7 request

        /**
         * $apiToken now be an instance of any ApiToken returned by the configured decoders under chain.list
         * So in our case, $apiToken can be either:
         *
         * - EonX\EasyApiToken\Interfaces\Tokens\BasicAuthEasyApiTokenInterface: BasicAuth provided
         * - EonX\EasyApiToken\Interfaces\Tokens\ApiKeyEasyApiTokenInterface: User ApiKey provided
         * - null: neither BasicAuth or User ApiKey provided
         */

        // Use the $apiToken...
    }
}

Required not to break format below

| Congratulations

The logic illustrated within the previous examples applies to any decoders, so you now know how to handle multiple authentication mechanism (ApiToken strategy) for any of your API endpoints and with only 3 lines of code!