Skip to content

symfony/symfony

6.2
Switch branches/tags
Code

Latest commit

This PR was merged into the 6.2 branch.

Discussion
----------

[Security] Access Token Authenticator

| Q             | A
| ------------- | ---
| Branch?       | 6.2
| Bug fix?      | yes
| New feature?  | yes<!-- please update src/**/CHANGELOG.md files -->
| Deprecations? | no
| Tickets       | Fix #45844
| License       | MIT
| Doc PR        | symfony/symfony-docs#16819

Hi,

This PR aims at fixing #45844.
It adds a new authenticator that is able to fetch a token in the request header and retrieve the associated user identifier.

The authenticator delegates the token loading to a handler. This handler could manage opaque tokens (random strings stored in a database) or self-contained tokens such as JWT, Paseto, SAML...

* [x] [RFC6750, section 2](https://datatracker.ietf.org/doc/html/rfc6750#section-2): Authenticated Requests
    * [x] Token in the request header ([section 2.1](https://datatracker.ietf.org/doc/html/rfc6750#section-2.1))
    * [x]  Token in the query string ([section 2.2](https://datatracker.ietf.org/doc/html/rfc6750#section-2.2))
    * [x]  Token in the request body ([section 2.3](https://datatracker.ietf.org/doc/html/rfc6750#section-2.3))
* [x] [RFC6750, section 3](https://datatracker.ietf.org/doc/html/rfc6750#section-3): The WWW-Authenticate Response Header Field
    * [x] [RFC6750, section 3.1](https://datatracker.ietf.org/doc/html/rfc6750#section-3.1): Error Codes
* [x] Documentation: see symfony/symfony-docs#16819
* [x] Tests

# Firewall Configuration

This PR adds a new authenticator that covers the RFC6750: `access_token`.
Also, it adds the possibility to extract the token from anywhere in the request.

## Basic Configuration

```yaml
security:
    firewalls:
        main:
            pattern: ^/
            access_token:
                token_handler: access_token.access_token_handler
```

## Complete Configuration

```yaml
security:
    firewalls:
        main:
            pattern: ^/
            access_token:
                user_provider: 'dedicate_user_provider_for_this_firewall'
                success_handler: 'custom_success_handler'
                failure_handler: 'custom_failure_handler'
                token_handler: access_token.access_token_handler
                token_extractors:
                    - 'security.access_token_extractor.query_string'
                    - 'security.access_token_extractor.request_body'
                    - 'security.access_token_extractor.header'
                    - 'custom_access_token_extractor'
```

# Token Handler

This authenticator relies on a Token Handler. Its responsability is to
* load the token
* check the token (revocation, expiration time, digital signature...)
* return the user ID associated to it

Tokens could be of any kind: opaque strings or self-contained tokens such as JWT, Paseto, SAML2...

## Example: from a repository

```php
<?php

namespace App\Security;

use App\Repository\AccessTokenRepository;
use Symfony\Component\Security\Core\Exception\BadCredentialsException;
use Symfony\Component\Security\Http\Authenticator\AccessTokenHandler as AccessTokenHandlerAliasInterface;

class AccessTokenHandler implements AccessTokenHandlerAliasInterface
{
    public function __construct(private readonly AccessTokenRepository $repository)
    {
    }

    public function getUserIdentifierFrom(string $token): string
    {
        $accessToken = $this->repository->findOneByValue($token);
        if ($accessToken === null || !$accessToken->isValid()) {
            throw new BadCredentialsException('Invalid credentials.');
        }

        return $accessToken->getUserId();
    }
}
```

## Example: from a JWT

```php
<?php

namespace App\Security;

use App\Security\JWTLoader;
use App\Security\JWTValidator;
use Symfony\Component\Security\Core\Exception\BadCredentialsException;
use Symfony\Component\Security\Http\Authenticator\AccessTokenHandler as AccessTokenHandlerAliasInterface;

class AccessTokenHandler implements AccessTokenHandlerAliasInterface
{
    public function __construct(
        private readonly JWTLoader $loader,
        private readonly JWTValidator $validator
    )
    {
    }

    public function getUserIdentifierFrom(string $token): string
    {
        try {
            $token = $this->loader->loadJWT($token);
            $this->validator->validate($token);

            return $token->getClaim('sub');
        } catch (\Throwable $e) {
            throw new BadCredentialsException('Invalid credentials.', $e->getCode, $e);
        }
    }
}
```

Commits
-------

e5873e8 [Security] Access Token Authenticator
dfcf900

Files

Permalink
Failed to load latest commit information.
Type
Name
Latest commit message
Commit time

Symfony is a PHP framework for web and console applications and a set of reusable PHP components. Symfony is used by thousands of web applications and most of the popular PHP projects.

Installation

Sponsor

Symfony 6.2 is backed by Les-Tilleuls.coop and Sulu.

Les-Tilleuls.coop is a team of 50+ Symfony experts who can help you design, develop and fix your projects. We provide a wide range of professional services including development, consulting, coaching, training and audits. We also are highly skilled in JS, Go and DevOps. We are a worker cooperative!

Sulu is the CMS for Symfony developers. It provides pre-built content-management features while giving developers the freedom to build, deploy, and maintain custom solutions using full-stack Symfony. Sulu is ideal for creating complex websites, integrating external tools, and building custom-built solutions.

Help Symfony by sponsoring its development!

Documentation

Community

Contributing

Symfony is an Open Source, community-driven project with thousands of contributors. Join them contributing code or contributing documentation.

Security Issues

If you discover a security vulnerability within Symfony, please follow our disclosure procedure.

About Us

Symfony development is led by the Symfony Core Team and supported by Symfony contributors.