k3progetti/jwt-bundle

Bundle Symfony per la gestione dei token JWT con supporto a refresh token e logout

Package info

github.com/K3Progetti/jwt-bundle

Type:symfony-bundle

pkg:composer/k3progetti/jwt-bundle

Statistics

Installs: 112

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

4.0.0 2026-03-28 20:02 UTC

Requires (Dev)

None

Suggests

None

Provides

None

Conflicts

None

Replaces

None

MIT f99bf6b0c703d6ea7aaa2e84898647a92bb31e01

  • Mattia Vitali <vitali.mattia.woop@gmail.com>

README

Bundle Symfony per la gestione avanzata dei token JWT, con supporto a:

  • Login e generazione token JWT
  • Autenticazione a due fattori (2FA)
  • Refresh token
  • Logout e invalidazione dei token
  • Payload JWT personalizzabile tramite interfaccia
  • Comandi da terminale per la pulizia dei token scaduti

Requisiti

  • PHP >= 8.2
  • Symfony ~8.0

Installazione

composer require k3progetti/jwt-bundle
php composer.phar install --ignore-platform-req=ext-redis

Configurazione

Registrazione del bundle

Aggiungi il bundle al tuo config/bundles.php se non viene registrato automaticamente:

return [
 // ...
 K3Progetti\JwtBundle\JwtBundle::class => ['all' => true],
];

Configurazione JWT (config/packages/jwt.yaml)

Copia il file di esempio resources/config/packages/jwt.yaml.dist e adattalo:

jwt:
 secret_key: '%env(JWT_PASSPHRASE)%'
 token_ttl: 3600 # Scadenza del token in secondi (default: 1 ora)
 refresh_token_ttl: 2592000 # Scadenza del refresh token in secondi (default: 30 giorni)
 algorithm: 'HS256' # Algoritmo di firma (default: HS256)
 time_zone: 'Europe/Rome' # Fuso orario (default: Europe/Rome)
 2fa_expired_code: 10 # ValiditΓ  codice 2FA in minuti (default: 10)
 user_class: 'App\Entity\User'
 user_repository_class: 'App\Repository\UserRepository'
 # mailer_class: 'App\Service\External\PostmarkService' # Richiesto solo se si usa il 2FA

Aggiungi nel tuo .env:

JWT_PASSPHRASE=la_tua_chiave_segreta

Configurazione del firewall (config/packages/security.yaml)

firewalls:
 api:
 pattern: ^/api/
 stateless: true
 custom_authenticator: K3Progetti\JwtBundle\Security\JwtAuthenticator

Implementazione delle interfacce

EntitΓ  utente β€” JwtUserInterface

La tua entitΓ  User deve implementare K3Progetti\JwtBundle\Security\JwtUserInterface:

use K3Progetti\JwtBundle\Security\JwtUserInterface;

class User implements JwtUserInterface
{
 public function getId(): mixed { ... }
 public function getUsername(): string { ... }
 public function getName(): string { ... }
 public function getSurname(): string { ... }
 public function isActive(): bool { ... }

 // Campi richiesti per il 2FA
 public function isTwoFactorAuth(): bool { ... }
 public function getTwoFactorAuthCode(): ?string { ... }
 public function setTwoFactorAuthCode(?string $code): static { ... }
 public function setTwoFactorAuthCodeExpired(\DateTimeInterface $dt): static { ... }
}

Repository utente β€” JwtUserRepositoryInterface

Il tuo UserRepository deve implementare K3Progetti\JwtBundle\Repository\JwtUserRepositoryInterface:

use K3Progetti\JwtBundle\Repository\JwtUserRepositoryInterface;
use K3Progetti\JwtBundle\Security\JwtUserInterface;

class UserRepository implements JwtUserRepositoryInterface
{
 public function findOneBy(array $criteria, ?array $orderBy = null): ?JwtUserInterface { ... }
 public function save(JwtUserInterface $user): void { ... }
}

Mailer 2FA β€” TwoFactorMailerInterface (opzionale)

Se vuoi abilitare il 2FA, implementa K3Progetti\JwtBundle\Mailer\TwoFactorMailerInterface e registra la classe in mailer_class:

use K3Progetti\JwtBundle\Mailer\TwoFactorMailerInterface;
use K3Progetti\JwtBundle\Security\JwtUserInterface;

class PostmarkService implements TwoFactorMailerInterface
{
 public function sendTwoFactorCode(JwtUserInterface $user, string $code): void { ... }
}

Payload personalizzato β€” JwtPayloadInterface (opzionale)

Per aggiungere dati custom al token JWT, implementa K3Progetti\JwtBundle\Service\JwtPayloadInterface e taggala come servizio:

use K3Progetti\JwtBundle\Service\JwtPayloadInterface;
use K3Progetti\JwtBundle\Security\JwtUserInterface;

class MyPayloadModifier implements JwtPayloadInterface
{
 // Aggiunge dati prima della costruzione del payload base
 public function onBeforePayload(JwtUserInterface $user): array { ... }

 // Modifica il payload dopo la costruzione base
 public function onAfterPayload(array $payload, JwtUserInterface $user): array { ... }

 // Sovrascrive completamente il payload (restituire null per non sovrascrivere)
 public function overridePayload(JwtUserInterface $user): ?array { ... }
}

Migrazioni

Il bundle include due entitΓ : JwtToken e JwtRefreshToken. Dopo aver installato il bundle, genera e applica le migrazioni:

php bin/console make:migration
php bin/console doctrine:migrations:migrate

Endpoint disponibili

Metodo URL Descrizione
POST /login_check Login standard
POST /login_check_2fa Login con codice 2FA
POST /token/refresh Rinnovo del token tramite refresh token
GET /api/logout Logout e invalidazione del token

Esempio login

POST /login_check
{
 "username": "utente@example.com",
 "password": "password"
}

Risposta:

{
 "token": "eyJ...",
 "refresh_token": "abc123..."
}

Esempio 2FA

Se l'utente ha il 2FA abilitato, il primo /login_check invia il codice via email. Il client deve poi completare il login su /login_check_2fa:

POST /login_check_2fa
{
 "username": "utente@example.com",
 "password": "password",
 "code": "123456"
}

Comandi Console

bin/console jwt:remove-jwt-refresh-token-expired # Rimuove i refresh token scaduti
bin/console jwt:remove-jwt-token-expired # Rimuove i token JWT scaduti
bin/console jwt:remove-jwt-token-user # Rimuove i token di un utente specifico

Struttura del Progetto

JwtBundle/
β”œβ”€β”€ JwtBundle.php
β”œβ”€β”€ resources/
β”‚ └── config/
β”‚ └── packages/
β”‚ └── jwt.yaml.dist
└── src/
 β”œβ”€β”€ Command/
 β”‚ β”œβ”€β”€ RemoveJwtRefreshTokenExpired.php
 β”‚ β”œβ”€β”€ RemoveJwtTokenExpired.php
 β”‚ └── RemoveJwtTokenUser.php
 β”œβ”€β”€ Controller/
 β”‚ └── AuthController.php
 β”œβ”€β”€ DependencyInjection/
 β”‚ β”œβ”€β”€ Configuration.php
 β”‚ └── JwtExtension.php
 β”œβ”€β”€ Entity/
 β”‚ β”œβ”€β”€ JwtToken.php
 β”‚ └── JwtRefreshToken.php
 β”œβ”€β”€ EventListener/
 β”‚ └── ExceptionListener.php
 β”œβ”€β”€ Exception/
 β”‚ └── JwtAuthorizationException.php
 β”œβ”€β”€ Helper/
 β”‚ └── AuthHelper.php
 β”œβ”€β”€ Http/
 β”‚ └── Result.php
 β”œβ”€β”€ Mailer/
 β”‚ └── TwoFactorMailerInterface.php
 β”œβ”€β”€ Repository/
 β”‚ β”œβ”€β”€ JwtRefreshTokenRepository.php
 β”‚ β”œβ”€β”€ JwtTokenRepository.php
 β”‚ └── JwtUserRepositoryInterface.php
 β”œβ”€β”€ Security/
 β”‚ β”œβ”€β”€ JwtAuthenticator.php
 β”‚ β”œβ”€β”€ JwtUserInterface.php
 β”‚ └── Handler/
 β”‚ β”œβ”€β”€ LoginHandler.php
 β”‚ β”œβ”€β”€ LogoutHandler.php
 β”‚ └── RefreshTokenHandler.php
 └── Service/
 β”œβ”€β”€ JwtPayloadInterface.php
 β”œβ”€β”€ JwtRefreshService.php
 └── JwtService.php

Contributi

Sono aperto a qualsiasi confronto.