---
title: "Add JWT Authentication to Your CakePHP API"
description: "Secure your CakePHP API using JWT authentication with JWKS."
canonicalUrl: "https://zuplo.com/use-cases/api-key-auth/php/cakephp/jwt-backend"
framework: "CakePHP"
language: "PHP"
authStrategy: "JWT with JWKS"
pageType: use-case
---

# Add JWT Authentication to Your CakePHP API

Secure your CakePHP API using JWT authentication with JWKS.

## How Zuplo Handles It

Let Zuplo issue short-lived JWTs signed with a JWKS your CakePHP backend can verify — no long-lived API keys touch your origin.

## CakePHP Backend Code

```php
use Firebase\JWT\JWT;
use Firebase\JWT\JWK;
use Cake\Http\MiddlewareQueue;
use Cake\Http\Middleware\AbstractMiddleware;
use Cake\Http\ServerRequest;
use Cake\Http\Response;

// Middleware to validate JWT
class JwtAuthenticationMiddleware extends AbstractMiddleware
{
    private $jwksUrl = 'https://my-api-a32f34.zuplo.api/__zuplo/issuer/.well-known/jwks.json';
    private $issuer = 'https://my-api-a32f34.zuplo.api/__zuplo/issuer';

    public function __invoke(ServerRequest $request, Response $response, callable $next)
    {
        $token = $this->getTokenFromHeader($request);

        if (!$token) {
            return $this->unauthorizedResponse($response, 'No token provided');
        }

        try {
            $keys = $this->getJwksKeys();
            $decoded = JWT::decode($token, $keys, ['RS256']);
            if ($decoded->iss !== $this->issuer) {
                throw new \Exception('Invalid issuer');
            }
            $request = $request->withAttribute('user', $decoded);

            return $next($request, $response);

        } catch (\Exception $e) {
            return $this->unauthorizedResponse($response, $e->getMessage());
        }
    }

    private function getTokenFromHeader(ServerRequest $request)
    {
        $authHeader = $request->getHeaderLine('Authorization');
        if (preg_match('/Bearer\s(\S+)/', $authHeader, $matches)) {
            return $matches[1];
        }
        return null;
    }

    private function unauthorizedResponse(Response $response, $message)
    {
        return $response
            ->withStatus(401)
            ->withStringBody(json_encode(['error' => $message]));
    }

    private function getJwksKeys()
    {
        $jwks = file_get_contents($this->jwksUrl);
        $keys = json_decode($jwks, true);
        return JWK::parseKeySet($keys);
    }
}

// In your Application.php or routes setup
public function middleware(MiddlewareQueue $middlewareQueue): MiddlewareQueue
{
    $middlewareQueue->add(JwtAuthenticationMiddleware::class);
    return $middlewareQueue;
}

// Example of a protected route in a controller
public function protectedData()
{
    $user = $this->request->getAttribute('user');
    return $this->response->withType('application/json')->withStringBody(json_encode([
        'message' => 'Access granted',
        'user' => $user,
    ]));
}
```

## Example Request

```bash
curl -X GET \
  'https://your-api.zuplo.dev/your-route' \
  -H 'Authorization: Bearer YOUR_API_KEY'
```

## Learn More

- [API Key Authentication on Zuplo](https://zuplo.com/docs/policies/api-key-auth-inbound)
- [JWT Authentication on Zuplo](https://zuplo.com/docs/policies/open-id-jwt-auth-inbound)
- [All use cases](https://zuplo.com/use-cases)
