IntegrateBackends
Symfony (PHP) integration
Validate Olympus tokens in a Symfony app
Symfony's Security component supports custom authenticators. We'll add one that validates Olympus OAuth2 access tokens.
Composer
composer require lcobucci/jwt firebase/php-jwt symfony/cacheJWKS fetcher with cache
// src/Security/JwksFetcher.php
namespace App\Security;
use Symfony\Contracts\Cache\CacheInterface;
use Symfony\Contracts\Cache\ItemInterface;
class JwksFetcher {
public function __construct(private CacheInterface $cache) {}
public function getKeys(): array {
return $this->cache->get('olympus_jwks', function (ItemInterface $item) {
$item->expiresAfter(3600);
$json = file_get_contents($_ENV['HYDRA_PUBLIC_URL'] . '/.well-known/jwks.json');
return json_decode($json, true);
});
}
}Authenticator
// src/Security/OlympusAuthenticator.php
namespace App\Security;
use Firebase\JWT\JWK;
use Firebase\JWT\JWT;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Security\Http\Authenticator\AbstractAuthenticator;
use Symfony\Component\Security\Http\Authenticator\Passport\Badge\UserBadge;
use Symfony\Component\Security\Http\Authenticator\Passport\SelfValidatingPassport;
class OlympusAuthenticator extends AbstractAuthenticator {
public function __construct(private JwksFetcher $jwks) {}
public function supports(Request $request): bool {
return $request->headers->has('Authorization');
}
public function authenticate(Request $request): SelfValidatingPassport {
$token = substr($request->headers->get('Authorization'), 7);
$jwks = JWK::parseKeySet($this->jwks->getKeys());
$claims = JWT::decode($token, $jwks);
// Verify issuer
if ($claims->iss !== $_ENV['HYDRA_PUBLIC_URL']) {
throw new \Exception('invalid_issuer');
}
return new SelfValidatingPassport(new UserBadge($claims->sub));
}
}Wire into security.yaml
security:
firewalls:
api:
pattern: ^/api
stateless: true
custom_authenticators:
- App\Security\OlympusAuthenticatorScope checks
In controllers:
#[Route('/api/orders/{id}', methods: ['DELETE'])]
public function delete(string $id, Security $security) {
$token = $security->getToken();
$scopes = explode(' ', $token->getAttribute('scope') ?? '');
if (!in_array('orders:write', $scopes)) {
throw new AccessDeniedException();
}
// ...
}