Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Jwt Auth Laravel Package

atlance/jwt-auth

View on GitHub
Deep Wiki
Context7
## Getting Started

### Minimal Steps
1. **Generate Keys**
   Run the provided OpenSSL commands in `docs/generate_keys.md` to create `private.pem` and `public.pem` files. Store them securely (e.g., `config/jwt/`).
   Example for `ES256`:
   ```bash
   openssl genpkey -out config/jwt/private.pem -algorithm EC -pkeyopt ec_paramgen_curve:prime256v1 -aes-256-cbc -pass pass:${APP_SECRET}
   openssl pkey -in config/jwt/private.pem -passin pass:${APP_SECRET} -out config/jwt/public.pem -pubout
  1. Install & Configure

    composer require atlance/jwt-auth ^7.0
    

    Copy the default config to config/packages/atlance_jwt_auth.yaml and update .env with:

    ATLANCE_JWT_AUTH_PRIVATE_KEY_PATH=%kernel.project_dir%/config/jwt/private.pem
    ATLANCE_JWT_AUTH_PUBLIC_KEY_PATH=%kernel.project_dir%/config/jwt/public.pem
    ATLANCE_JWT_AUTH_ALGORITHM=ES256  # or RS256, ES384, etc.
    
  2. First Use Case: Login Endpoint Create a controller using the Create\Token\Handler to issue JWTs:

    #[Route('/login', methods: ['POST'])]
    public function login(
        Request $request,
        UserProviderInterface $userProvider,
        UserPasswordHasherInterface $passwordHasher,
        HandlerInterface $tokenHandler
    ): JsonResponse {
        $data = json_decode($request->getContent(), true);
        $user = $userProvider->loadUserByIdentifier($data['username']);
        if (!$passwordHasher->isPasswordValid($user, $data['password'])) {
            return new JsonResponse(['error' => 'Invalid credentials'], 401);
        }
        return new JsonResponse(['token' => $tokenHandler->handle($user)]);
    }
    
  3. Protect Routes Update security.yaml to enable JWT access:

    security:
        firewalls:
            main:
                access_token:
                    token_handler: Atlance\JwtAuth\Security\Factory\UserBadgeFactory
    

    Now, annotate controllers with [IsGranted] to enforce authentication:

    #[IsGranted('ROLE_USER')]
    #[Route('/profile')]
    public function profile(#[CurrentUser] UserInterface $user): JsonResponse {
        return new JsonResponse(['username' => $user->getUserIdentifier()]);
    }
    

Implementation Patterns

Workflows

  1. Token Issuance

    • Use Create\Token\HandlerInterface to generate JWTs for authenticated users.
    • Customize payload via dependency injection (e.g., add exp, iat, or custom claims):
      $handler->handle($user, [
          'exp' => (new \DateTimeImmutable('+1 hour'))->getTimestamp(),
          'custom_claim' => 'value',
      ]);
      
  2. Token Validation

    • The package integrates with Symfony’s AccessTokenAuthenticator, so validation is automatic.
    • Access the authenticated user via [CurrentUser] attribute or $this->getUser() in controllers.
  3. Role-Based Access

    • Leverage Symfony’s voter system or [IsGranted] attributes:
      #[IsGranted('ROLE_ADMIN')]
      public function adminDashboard(): JsonResponse { ... }
      
  4. Refresh Tokens

    • Implement a refresh endpoint using the same HandlerInterface with a longer expiry:
      $refreshTokenHandler->handle($user, ['exp' => (new \DateTimeImmutable('+7 days'))->getTimestamp()]);
      

Integration Tips

  • Custom User Providers Extend Symfony’s UserProviderInterface to fetch users from databases/APIs:

    class CustomUserProvider implements UserProviderInterface {
        public function loadUserByIdentifier(string $identifier): UserInterface {
            return $this->userRepository->findByUsername($identifier);
        }
        // ... other methods
    }
    
  • Token Storage Store JWTs in HTTP-only cookies for better security (use Symfony’s Response helpers):

    $response = new JsonResponse();
    $response->headers->setCookie(new Cookie('jwt', $token, [
        'httponly' => true,
        'secure' => true,
        'samesite' => 'Strict',
        'expires' => (new \DateTimeImmutable('+1 hour'))->format('D, d M Y H:i:s T'),
    ]));
    
  • Testing Mock the HandlerInterface or use Symfony’s TestClient with pre-authenticated requests:

    $client = static::createClient();
    $client->request('POST', '/login', [], [], [
        'HTTP_Authorization' => 'Bearer ' . $validToken,
    ]);
    

Gotchas and Tips

Pitfalls

  1. Key Management

    • Never commit private keys to version control. Use environment variables or secure vaults.
    • Algorithm Mismatch: Ensure the ALGORITHM in .env matches the key type (e.g., ES256 for EC keys, RS256 for RSA).
  2. Token Expiry

    • Default expiry is 1 hour. Adjust in config or handler:
      atlance_jwt_auth:
          ttl: 3600  # 1 hour in seconds
      
    • Clock Skew: Ensure server times are synchronized to avoid premature token invalidation.
  3. User Provider Quirks

    • loadUserByIdentifier must return a UserInterface. Custom users must implement this interface.
    • Case Sensitivity: Usernames/identifiers may be case-sensitive depending on your provider.
  4. Symfony Integration

    • Firewall Configuration: Forgetting to add access_token to a firewall will break JWT auth.
    • CORS: If using APIs, ensure CORS headers allow Authorization headers:
      # config/packages/nelmio_cors.yaml
      path_patterns:
          - ^/api
      allow_credentials: true
      allow_headers: ['Authorization']
      

Debugging

  1. Invalid Tokens

    • Check the public.pem path in .env and ensure it’s readable.
    • Validate token format (must be Bearer <token>).
  2. Permission Denied

    • Verify [IsGranted] roles match the user’s roles (e.g., ROLE_USER).
    • Use dd($user->getRoles()) to debug user roles.
  3. Performance

    • Key Loading: Large RSA keys (e.g., 4096-bit) may slow down token validation. Monitor with Symfony’s profiler.
    • Database Queries: Ensure UserProvider is optimized (e.g., indexed usernames).

Extension Points

  1. Custom Claims Extend the HandlerInterface to add dynamic claims:

    class CustomTokenHandler implements HandlerInterface {
        public function handle(UserInterface $user, array $customClaims = []): string {
            $claims = array_merge($customClaims, [
                'user_id' => $user->getId(),
                'scopes' => $user->getRoles(),
            ]);
            return $this->jwtBuilder->build($claims);
        }
    }
    
  2. Token Revocation Implement a blacklist or short-lived tokens with refresh logic:

    // Store revoked tokens in a database table
    $revokedTokens = $this->revokedTokenRepository->findBy(['token' => $token]);
    if ($revokedTokens->count() > 0) {
        throw new \Symfony\Component\Security\Core\Exception\AuthenticationException();
    }
    
  3. Multi-Tenancy Add tenant ID to the JWT payload:

    $handler->handle($user, ['tenant_id' => $user->getTenantId()]);
    

    Then validate in middleware:

    $tenantId = $token->getClaim('tenant_id');
    if ($tenantId !== $request->get('tenant_id')) {
        throw new AccessDeniedException();
    }
    
  4. Logging Log token issuance/rejection for auditing:

    $this->logger->info('JWT issued', [
        'user_id' => $user->getId(),
        'ip' => $request->getClientIp(),
    ]);
    

Configuration Quirks

  • TTL Units: The ttl in config is in seconds, not minutes/hours.
  • Clock Provider: The package uses Symfony’s ClockInterface. Override for testing:
    services:
        Symfony\Component\Clock\ClockInterface: '@custom_clock'
    
  • Public Key Path: Must be an absolute path or resolvable via Symfony’s parameter system.

Pro Tips

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
comsave/common
alecsammon/php-raml-parser
chrome-php/wrench
lendable/composer-license-checker
typhoon/reflection
mesilov/moneyphp-percentage
mike42/gfx-php
bookdown/themes
aura/view
aura/html
aura/cli
povils/phpmnd
nayjest/manipulator
omnipay/tests
psr-mock/http-message-implementation
psr-mock/http-factory-implementation
psr-mock/http-client-implementation
voku/email-check
voku/urlify
rtheunissen/guzzle-log-middleware