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

Oauth2 Server Laravel Package

league/oauth2-server

Standards-compliant OAuth 2.0 authorization server for PHP. Protect APIs with bearer access tokens, issue and refresh tokens, and support common grants (auth code, client credentials, device, implicit, password, refresh) with PSR-7 interoperability and RFC support.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup in Laravel

  1. Install the package:

    composer require league/oauth2-server
    
  2. Create a basic OAuth server instance (typically in a service provider):

    use League\OAuth2\Server\AuthorizationServer;
    use League\OAuth2\Server\Grant\AuthCodeGrant;
    use League\OAuth2\Server\Grant\ClientCredentialsGrant;
    use League\OAuth2\Server\Grant\RefreshTokenGrant;
    use League\OAuth2\Server\Grant\PasswordGrant;
    use League\OAuth2\Server\ResourceServer;
    
    // Define your entity implementations (see Implementation Patterns)
    $authorizationServer = new AuthorizationServer(
        $entityManager, // Your entity manager (e.g., Doctrine)
        $cryptKey,       // CryptKeyInterface
        $serverMiddleware,
        $grantTypes = [
            new AuthCodeGrant($accessTokenTTL, $refreshTokenTTL),
            new ClientCredentialsGrant($accessTokenTTL),
            new RefreshTokenGrant($refreshTokenTTL),
            new PasswordGrant($accessTokenTTL, $refreshTokenTTL),
        ],
        $scopeManager = null,
        $entityManager->getRepository(ClientEntity::class),
        $entityManager->getRepository(AccessTokenEntity::class),
        $entityManager->getRepository(RefreshTokenEntity::class),
        $entityManager->getRepository(AuthCodeEntity::class),
        $entityManager->getRepository(ScopeEntity::class)
    );
    
  3. First use case: Protect an API endpoint

    use League\OAuth2\Server\ResourceServer;
    
    $resourceServer = new ResourceServer(
        $cryptKey,
        $serverMiddleware,
        $entityManager->getRepository(AccessTokenEntity::class)
    );
    
    // In your Laravel route/middleware:
    $psr7Request = $request->toPsr7();
    $psr7Response = new \Laminas\Diactoros\Response();
    
    try {
        $server = $resourceServer->validateAuthenticatedRequest($psr7Request);
        // Proceed with authenticated logic
    } catch (\League\OAuth2\Server\Exception\OAuthServerException $exception) {
        return response()->json($exception->generateHttpResponse($psr7Response)->getBody()->getContents(), $exception->getHttpStatusCode());
    }
    

Key First Steps

  • Define your entities (Client, AccessToken, AuthCode, etc.) extending League’s interfaces.
  • Configure grants based on your API’s needs (e.g., AuthCodeGrant for web apps, ClientCredentialsGrant for machine-to-machine).
  • Integrate with Laravel’s middleware (e.g., HandleOAuth2Validation middleware).
  • Test with Postman/cURL using the OAuth 2.0 Playground.

Implementation Patterns

1. Entity Management

Leverage Laravel’s Eloquent models to implement League’s interfaces:

use League\OAuth2\Server\Entity\ClientEntityInterface;
use League\OAuth2\Server\Entity\AccessTokenEntityInterface;

class Client extends Model implements ClientEntityInterface {
    use \League\OAuth2\Server\Entity\Traits\ClientTrait;
    // Add Eloquent fields: id, secret, name, etc.
}

class AccessToken extends Model implements AccessTokenEntityInterface {
    use \League\OAuth2\Server\Entity\Traits\AccessTokenTrait;
    // Add Eloquent fields: id, token, user_id, expires_at, etc.
}

2. Grant-Specific Workflows

Authorization Code Grant (Web Apps)

  1. Redirect to OAuth endpoint:
    $authorizationRequest = $authorizationServer->createAuthorizationRequest(
        'https://your-app.com/callback',
        'random_state_string',
        ['scope1', 'scope2']
    );
    return redirect($authorizationRequest->getAuthorizationUri());
    
  2. Handle callback:
    $authCode = $authorizationServer->validateAuthorizationRequest(
        $request->query->all(),
        $request->get('state')
    );
    $tokenRequest = $authorizationServer->createTokenRequest(
        $authCode->getIdentifier(),
        $authCode->getClient()->getIdentifier(),
        $authCode->getClient()->getSecret(),
        $authCode->getRedirectUri(),
        $authCode->getScopes()
    );
    $accessToken = $authorizationServer->issueAccessToken($tokenRequest);
    

Client Credentials Grant (APIs)

$client = $entityManager->getRepository(ClientEntity::class)->find('client_id');
$tokenRequest = $authorizationServer->createTokenRequest(
    null, // No auth code
    $client->getIdentifier(),
    $client->getSecret(),
    null, // No redirect URI
    ['api:write'] // Scopes
);
$accessToken = $authorizationServer->issueAccessToken($tokenRequest);

3. Middleware Integration

Create a Laravel middleware to validate tokens:

use League\OAuth2\Server\ResourceServer;

class HandleOAuth2Validation {
    protected $server;

    public function __construct() {
        $this->server = new ResourceServer(
            $cryptKey,
            $serverMiddleware,
            $entityManager->getRepository(AccessTokenEntity::class)
        );
    }

    public function handle($request, Closure $next) {
        $psr7Request = $request->toPsr7();
        try {
            $this->server->validateAuthenticatedRequest($psr7Request);
            return $next($request);
        } catch (\League\OAuth2\Server\Exception\OAuthServerException $e) {
            return response()->json([
                'error' => $e->getErrorCode(),
                'error_description' => $e->getErrorDescription()
            ], $e->getHttpStatusCode());
        }
    }
}

4. Scope Management

Define scopes in a Laravel model:

class Scope extends Model implements ScopeEntityInterface {
    use \League\OAuth2\Server\Entity\Traits\ScopeTrait;
    // Fields: id, identifier (e.g., 'read:profile')
}

Use a ScopeManager to validate scopes:

$scopeManager = new \League\OAuth2\Server\Scope\ScopeManager(
    $entityManager->getRepository(ScopeEntity::class)
);
$authorizationServer = new AuthorizationServer(/* ... */, $scopeManager);

5. Refresh Tokens

Handle refresh token requests:

$refreshToken = $entityManager->getRepository(RefreshTokenEntity::class)->find('refresh_token_id');
$tokenRequest = $authorizationServer->createTokenRequest(
    null, // No auth code
    $refreshToken->getClient()->getIdentifier(),
    $refreshToken->getClient()->getSecret(),
    null, // No redirect URI
    $refreshToken->getScopes()
);
$accessToken = $authorizationServer->issueAccessToken($tokenRequest);

6. PKCE (Proof Key for Code Exchange)

Enable PKCE for public clients:

$grant = new AuthCodeGrant($accessTokenTTL, $refreshTokenTTL);
$grant->setUsePKCE(true); // Enable PKCE
$authorizationServer = new AuthorizationServer(/* ... */, [$grant]);

Gotchas and Tips

Common Pitfalls

  1. Case Sensitivity in Headers

    • Bearer tokens in the Authorization header are case-insensitive (fixed in v9.3.0), but ensure your middleware handles this correctly.
    • Example: Authorization: Bearer TOKEN or authorization: bearer token both work.
  2. Refresh Token Revocation

    • Disabling refresh token revocation with revokeRefreshTokens(false) does not disable issuing new refresh tokens (fixed in v9.0.1). Use GrantTypeInterface::revokeRefreshTokens() carefully.
  3. Scope Validation

    • Scopes are case-sensitive by default. Normalize them (e.g., strtolower()) if needed.
    • Always validate scopes before issuing tokens to avoid invalid_scope errors.
  4. State Parameter

    • The state parameter must be unique and unguessable (e.g., CSRF tokens). Omitting it in implicit grants can lead to security issues.
  5. Redirect URIs

    • Always validate redirect URIs against registered client URIs. Use UriInterface for strict validation:
      $uri = new \League\Uri\Uri($redirectUri);
      if (!$client->getRegisteredRedirectUris()->contains($uri)) {
          throw new \League\OAuth2\Server\Exception\OAuthServerException(
              'invalid_request',
              'Redirect URI mismatch',
              \Symfony\Component\HttpFoundation\Response::HTTP_BAD_REQUEST
          );
      }
      
  6. Token Expiration

    • Tokens expire at exactly the expires_at time (not "after"). Use Carbon for precise timestamps:
      $expiresAt = now()->addMinutes($accessTokenTTL)->timestamp;
      
  7. **PKCE Downg

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.
calmfox/watch-sylius
damienfern/grpc-symfony-bundle
atoolo/index-bundle
atoolo/genai-bundle
coprotoai/laravel-ticket
davidjln/llm-carbon-bundle
cryonighter/valid-request-bundle
coolms/taxonomy-bundle
coolms/field-bundle
articulate-orm/symfony
aaix/laravel-tall-architect
ephoto/akeneo-connector
emmanuelballery/eb-plantumlbundle
emielburgman/symfony-visitor-beacon
emielburgman/symfony-visit-storage
emielburgman/symfony-security-headers
emielburgman/symfony-log-viewer
emarref/xdebug-bundle
emarref/pubnub-bundle
elriseio/finance-money-bundle