kematjaya/auth-bundle

API-first JWT authentication & simple RBAC for Symfony (API Platform friendly). Bring your own User entity via a small interface + factory contract.

Maintainers

Package info

github.com/kematjaya0/auth-bundle

Type:symfony-bundle

pkg:composer/kematjaya/auth-bundle

Transparency log

Statistics

Installs: 0

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

1.0 2026-08-10 10:38 UTC

This package is auto-updated.

Last update: 2026-08-10 10:42:14 UTC


README

API-first, stateless JWT authentication and simple array-based RBAC for Symfony. Built for apps exposing a JSON API (API Platform friendly) consumed by a decoupled frontend (e.g. Next.js) - not for server-rendered/session apps. For that use case, see kematjaya/user-bundle instead.

Ships: register, login (via lexik/jwt-authentication-bundle), refresh (via gesdinet/jwt-refresh-token-bundle), logout (refresh token revocation), change password, GET /api/me, a per-IP+email rate limiter on login/register, and an optional API Platform OpenAPI documentation decorator.

No UI. Frontend integration (Next.js) is a separate package, @kematjaya/auth-ui.

Why "bring your own User entity"

Your app almost certainly already has a User entity referenced by other domain entities (e.g. Note.owner). This bundle can't own that class - it would create a circular dependency (the bundle can't depend on the app that depends on it), and it would make the entity disappear the moment the bundle is removed, breaking every relation to it.

Instead the bundle depends on two small interfaces from Kematjaya\AuthBundle\Contract:

  • AuthenticatableUserInterface - your User entity implements this (it already satisfies most of it if it implements Symfony's own UserInterface + PasswordAuthenticatedUserInterface).
  • UserManagerInterface - your app provides one implementation (typically a thin Doctrine-backed class) that finds/creates/persists your User. See .recipe/src/Security/UserManager.php for a ready-to-adapt example.

Installation

Requirements

  • PHP 8.4+, Symfony 7.0+ or 8.0+
  • symfony/security-bundle, doctrine/doctrine-bundle + doctrine/orm in your app (see composer.json for the full list this bundle requires)
  • A database Doctrine can reach (DATABASE_URL set in .env/.env.local)

Quick install

composer require kematjaya/auth-bundle
bash vendor/kematjaya/auth-bundle/setup.sh

You'll likely see a cache:clear error flash by right after composer require finishes. That's expected, not a failure: Gesdinet's bundle needs config that setup.sh hasn't copied in yet at that point in time. The package itself installs fine - ignore the error and run setup.sh.

That's it for a fresh project with no User entity yet. If you already have one, see Bring your own User entity below before running setup.sh.

What setup.sh does

It's idempotent - safe to re-run any time, it skips any file that already exists (--force to overwrite). It exists because this bundle isn't published to a Flex recipes endpoint yet, so it does by hand everything a real recipe would do automatically on composer require:

# Step Result
1 Registers the bundle adds a line to config/bundles.php
2 Copies config fragments config/packages/lexik_jwt_authentication.yaml, gesdinet_jwt_refresh_token.yaml, kematjaya_auth_doctrine_types.yaml (registers the Doctrine uuid type the User template below uses), config/routes/kematjaya_auth.yaml
3 Copies User plumbing src/Entity/User.php, src/Repository/UserRepository.php, src/Security/UserManager.php - skipped if you already have your own
4 Wires the DI binding Kematjaya\AuthBundle\Contract\UserManagerInterface -> App\Security\UserManager in config/services.yaml
5 Generates the JWT keypair lexik:jwt:generate-keypair --skip-if-exists, appends JWT_SECRET_KEY/JWT_PUBLIC_KEY/JWT_PASSPHRASE to .env (change the passphrase before deploying!)
6 Updates the schema php bin/console doctrine:schema:update --force

The one manual step

setup.sh prints this reminder at the end - it is not automated on purpose:

Merge config/packages/kematjaya_auth_security.yaml.dist into your own config/packages/security.yaml (providers / firewalls / access_control). It was copied with a .dist suffix specifically so Symfony does not auto-load it - it auto-loads every .yaml file under config/packages/, and dropping a second firewalls: main: definition there would collide with the one your app's skeleton already has. Open both files side by side and merge the relevant blocks in yourself.

Until that merge is done, the bundle's routes exist but nothing is authenticated or protected by JWT.

Also double check that symfony/security-bundle, lexik/jwt-authentication-bundle, and gesdinet/jwt-refresh-token-bundle all ended up registered in config/bundles.php. Most auto-register via their own official Flex recipes, but --no-interaction/CI installs sometimes skip contrib recipes - setup.sh only registers this bundle, not its dependencies' bundles.

Bring your own User entity

If you already have a User entity (most real projects will), put it at src/Entity/User.php before running setup.sh so step 3 skips it instead of overwriting it. If you already ran setup.sh, just delete the copied file and put your own there instead. Then:

  1. Make your entity implements Kematjaya\AuthBundle\Contract\AuthenticatableUserInterface.
  2. Adapt src/Security/UserManager.php (still copied by setup.sh) to your entity/repository.

See Why "bring your own User entity" above for why this last part can't be automated further.

Uninstall (clean baseline)

composer remove kematjaya/auth-bundle, remove the bundle line from config/bundles.php, remove src/Security/UserManager.php and the kematjaya_auth_* files under config/packages/ and config/routes/, and remove the merged block from your own security.yaml. Your User entity stays untouched (it never depended on this bundle at the class level) - only remove the implements AuthenticatableUserInterface clause if you want it gone too.

Endpoints

Method Path Auth required
POST /api/register no
POST /api/login no
POST /api/token/refresh no
POST /api/logout no (revokes by possession of the refresh token)
GET /api/me yes
POST /api/change-password yes

Configuration

None. This bundle is intentionally zero-config - see the "Why bring your own User entity" section for why a user_class option was deliberately avoided. The rate limiter (5 requests/minute per IP+email on /api/login and /api/register) can be overridden by defining framework.rate_limiter.kematjaya_auth_authentication yourself before this bundle's prependExtension() runs, i.e. in your own config/packages/framework.yaml.

Testing

composer install
composer test