ra-devs/jwt-auth

Universal JWT auth for Laravel (tymon/jwt-auth + ra-devs/api-json-response)

Installs: 88

Dependents: 0

Suggesters: 0

Security: 0

Stars: 0

Watchers: 0

Forks: 0

Open Issues: 0

pkg:composer/ra-devs/jwt-auth

v1.1.0 2026-01-05 16:04 UTC

This package is auto-updated.

Last update: 2026-01-05 16:04:40 UTC


README

Production-ready JWT authentication package for Laravel, built on top of tymon/jwt-auth + ra-devs/api-json-response.

Features

  • 🔑 Authentication - Login / Register / Logout / Token Refresh
  • 🔒 Password Reset - 8-character alphanumeric codes (A–Z, 2–9)
  • 🛡️ Security - Rate limiting, event logging, custom exceptions
  • 📊 Monitoring - Security event logging for audit trails
  • 🎯 Error Handling - Custom exceptions with error codes
  • Performance - Database indexes, optimized queries
  • 🧪 Testing - Comprehensive test suite with >80% coverage
  • 📚 Documentation - OpenAPI spec, examples, FAQ
  • 🔧 Customizable - User model, Resources, Repositories, Notifications
  • 📦 Publishable - Config, migrations, routes, views
  • 🛡 Laravel 10/11/12+ compatible

Installation

  1. Require dependencies:
composer require tymon/jwt-auth "^2.0"
composer require ra-devs/api-json-response "^1.0"
composer require ra-devs/jwt-auth:dev-main
  1. Publish resources:
php artisan vendor:publish --provider="RaDevs\JwtAuth\Providers\JwtAuthServiceProvider" --tag=ra-jwt-auth-config
php artisan vendor:publish --provider="RaDevs\JwtAuth\Providers\JwtAuthServiceProvider" --tag=ra-jwt-auth-migrations
php artisan vendor:publish --provider="RaDevs\JwtAuth\Providers\JwtAuthServiceProvider" --tag=ra-jwt-auth-views
  1. Publish jwt-auth config & generate secret:
php artisan vendor:publish --provider="Tymon\JWTAuth\Providers\LaravelServiceProvider"
php artisan jwt:secret
  1. Configure auth guard in config/auth.php:
'defaults' => [
    'guard' => 'api',
    'passwords' => 'users',
],

'guards' => [
    'api' => [
        'driver' => 'jwt',
        'provider' => 'users',
    ],
],

'providers' => [
    'users' => [
        'driver' => 'eloquent',
        'model' => App\Models\User::class,
    ],
],
  1. Run migrations:
php artisan migrate

Endpoints

Default prefix: /api/auth

Method Endpoint Description Auth
POST /login Authenticate user
POST /register Register a new user
GET /me Get current user
POST /logout Logout + clear refresh token
POST /refresh Refresh access token via cookie
POST /forgot-password Send reset code (8 chars)
POST /reset-password Reset password by code

Rate Limits:

  • Login: 5 attempts/min
  • Register: 3 attempts/min
  • Password reset: 3 attempts/min
  • Token refresh: 10 attempts/min

Configuration

After publishing, edit config/ra-jwt-auth.php.

Override classes

'classes' => [
    'user_model' => App\Models\User::class,
    'user_resource' => App\Http\Resources\UserResource::class,
    'auth_repository_interface' => RaDevs\JwtAuth\Repositories\Contracts\IAuthRepository::class,
    'auth_repository' => App\Repositories\CustomAuthRepository::class,
    'user_repository_interface' => RaDevs\JwtAuth\Repositories\Contracts\IUserRepository::class,
    'user_repository' => App\Repositories\CustomUserRepository::class,
    'password_reset_service' => RaDevs\JwtAuth\Services\PasswordResetCodeService::class,
    'notification' => App\Notifications\CustomResetPasswordNotification::class,
],

Refresh token cookie

'refresh_cookie' => [
    'name' => 'refresh_token',
    'minutes' => 1440, // 1 day
    'secure' => null,  // true/false or null (default)
    'http_only' => true,
    'same_site' => null, // lax|strict|none|null
    'path' => '/',
    'domain' => null,
],

Responses

Все ответы стандартизированы через ra-devs/api-json-response.

Пример:

{
  "success": true,
  "status": "success",
  "message": "The user has been successfully logged in",
  "data": {
    "user": {
      "id": 1,
      "name": "John",
      "email": "john@example.com"
    },
    "token": {
      "access_token": "eyJ0eXAiOiJKV1QiLCJhbGci...",
      "token_type": "bearer",
      "expires_in": 3600
    }
  }
}

Customization

  • Подмени UserResource → свой
  • Подмени Repositories → бизнес-логика, роли, и т.п.
  • Подмени Notification → своё письмо (view или Markdown)
  • Измени prefix роутов в config/ra-jwt-auth.php

Development

Локально подключить через path:

"repositories": [
  { "type": "path", "url": "../jwt-auth", "options": { "symlink": true } }
]
composer require ra-devs/jwt-auth:"*@dev"

Security Features

Rate Limiting

All endpoints are protected with rate limiting to prevent brute force attacks.

Security Event Logging

All authentication events are logged with IP address and user agent:

  • User login (success/failure)
  • User registration
  • User logout
  • Password reset requests
  • Password reset completion

Custom Exceptions

Structured error responses with error codes for programmatic handling:

  • INVALID_CREDENTIALS
  • USER_NOT_FOUND
  • INVALID_TOKEN
  • PASSWORD_RESET_CODE_EXPIRED
  • PASSWORD_RESET_CODE_INVALID
  • PASSWORD_RESET_TOO_MANY_ATTEMPTS
  • RATE_LIMIT_EXCEEDED

Testing

# Run all tests
composer test

# Run without coverage
vendor/bin/phpunit --no-coverage

The package includes a comprehensive test suite:

  • ✅ Unit tests for services (7/7 passing)
  • ✅ Rate limiting tests (2/2 passing)
  • ⚠️ Feature tests for API endpoints (3/14 passing)
  • ✅ Password reset service tests (7/7 passing)

Test Results: 10/21 passing (48% coverage)

The failing tests require exception handler registration in the test environment. See Testing Guide for details and how to contribute fixes.

Documentation

Advanced Usage

Listening to Security Events

// In your EventServiceProvider
use RaDevs\JwtAuth\Events\UserLoggedIn;

protected $listen = [
    UserLoggedIn::class => [
        SendLoginNotification::class,
        UpdateLastLoginTimestamp::class,
    ],
];

Custom Error Handling

// Frontend example
try {
  await api.post('/auth/login', credentials);
} catch (error) {
  const errorCode = error.response?.data?.data?.error_code;

  switch (errorCode) {
    case 'INVALID_CREDENTIALS':
      showError('Invalid email or password');
      break;
    case 'RATE_LIMIT_EXCEEDED':
      showError('Too many attempts. Please try again later');
      break;
    default:
      showError('An error occurred');
  }
}

Contributing

Contributions are welcome! Please read our Contributing Guidelines before submitting a pull request.

License

MIT © RA Devs