ubah ke docker mode

This commit is contained in:
servdal
2025-07-16 07:36:13 +07:00
parent 6871d14f94
commit 9471bf22f5
15161 changed files with 112 additions and 0 deletions

No files matched your search

@@ -0,0 +1,82 @@
<?php
namespace Laravel\Passport;
use Carbon\Carbon;
use Firebase\JWT\JWT;
use Illuminate\Contracts\Config\Repository as Config;
use Illuminate\Contracts\Encryption\Encrypter;
use Symfony\Component\HttpFoundation\Cookie;
class ApiTokenCookieFactory
{
/**
* The configuration repository implementation.
*
* @var \Illuminate\Contracts\Config\Repository
*/
protected $config;
/**
* The encrypter implementation.
*
* @var \Illuminate\Contracts\Encryption\Encrypter
*/
protected $encrypter;
/**
* Create an API token cookie factory instance.
*
* @param \Illuminate\Contracts\Config\Repository $config
* @param \Illuminate\Contracts\Encryption\Encrypter $encrypter
* @return void
*/
public function __construct(Config $config, Encrypter $encrypter)
{
$this->config = $config;
$this->encrypter = $encrypter;
}
/**
* Create a new API token cookie.
*
* @param mixed $userId
* @param string $csrfToken
* @return \Symfony\Component\HttpFoundation\Cookie
*/
public function make($userId, $csrfToken)
{
$config = $this->config->get('session');
$expiration = Carbon::now()->addMinutes($config['lifetime']);
return new Cookie(
Passport::cookie(),
$this->createToken($userId, $csrfToken, $expiration),
$expiration,
$config['path'],
$config['domain'],
$config['secure'],
true,
false,
$config['same_site'] ?? null
);
}
/**
* Create a new JWT token for the given user ID and CSRF token.
*
* @param mixed $userId
* @param string $csrfToken
* @param \Carbon\Carbon $expiration
* @return string
*/
protected function createToken($userId, $csrfToken, Carbon $expiration)
{
return JWT::encode([
'sub' => $userId,
'csrf' => $csrfToken,
'expiry' => $expiration->getTimestamp(),
], Passport::tokenEncryptionKey($this->encrypter), 'HS256');
}
}
+63
View File
@@ -0,0 +1,63 @@
<?php
namespace Laravel\Passport;
use Illuminate\Database\Eloquent\Model;
class AuthCode extends Model
{
/**
* The database table used by the model.
*
* @var string
*/
protected $table = 'oauth_auth_codes';
/**
* Indicates if the IDs are auto-incrementing.
*
* @var bool
*/
public $incrementing = false;
/**
* The guarded attributes on the model.
*
* @var array
*/
protected $guarded = [];
/**
* The attributes that should be cast to native types.
*
* @var array
*/
protected $casts = [
'revoked' => 'bool',
'expires_at' => 'datetime',
];
/**
* Indicates if the model should be timestamped.
*
* @var bool
*/
public $timestamps = false;
/**
* The "type" of the primary key ID.
*
* @var string
*/
protected $keyType = 'string';
/**
* Get the client that owns the authentication code.
*
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function client()
{
return $this->belongsTo(Passport::clientModel());
}
}
@@ -0,0 +1,33 @@
<?php
namespace Laravel\Passport\Bridge;
use League\OAuth2\Server\Entities\AccessTokenEntityInterface;
use League\OAuth2\Server\Entities\ClientEntityInterface;
use League\OAuth2\Server\Entities\Traits\AccessTokenTrait;
use League\OAuth2\Server\Entities\Traits\EntityTrait;
use League\OAuth2\Server\Entities\Traits\TokenEntityTrait;
class AccessToken implements AccessTokenEntityInterface
{
use AccessTokenTrait, EntityTrait, TokenEntityTrait;
/**
* Create a new token instance.
*
* @param string $userIdentifier
* @param array $scopes
* @param \League\OAuth2\Server\Entities\ClientEntityInterface $client
* @return void
*/
public function __construct($userIdentifier, array $scopes, ClientEntityInterface $client)
{
$this->setUserIdentifier($userIdentifier);
foreach ($scopes as $scope) {
$this->addScope($scope);
}
$this->setClient($client);
}
}
@@ -0,0 +1,91 @@
<?php
namespace Laravel\Passport\Bridge;
use DateTime;
use Illuminate\Contracts\Events\Dispatcher;
use Laravel\Passport\Events\AccessTokenCreated;
use Laravel\Passport\Passport;
use Laravel\Passport\TokenRepository;
use League\OAuth2\Server\Entities\AccessTokenEntityInterface;
use League\OAuth2\Server\Entities\ClientEntityInterface;
use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface;
class AccessTokenRepository implements AccessTokenRepositoryInterface
{
use FormatsScopesForStorage;
/**
* The token repository instance.
*
* @var \Laravel\Passport\TokenRepository
*/
protected $tokenRepository;
/**
* The event dispatcher instance.
*
* @var \Illuminate\Contracts\Events\Dispatcher
*/
protected $events;
/**
* Create a new repository instance.
*
* @param \Laravel\Passport\TokenRepository $tokenRepository
* @param \Illuminate\Contracts\Events\Dispatcher $events
* @return void
*/
public function __construct(TokenRepository $tokenRepository, Dispatcher $events)
{
$this->events = $events;
$this->tokenRepository = $tokenRepository;
}
/**
* {@inheritdoc}
*/
public function getNewToken(ClientEntityInterface $clientEntity, array $scopes, $userIdentifier = null)
{
return new Passport::$accessTokenEntity($userIdentifier, $scopes, $clientEntity);
}
/**
* {@inheritdoc}
*/
public function persistNewAccessToken(AccessTokenEntityInterface $accessTokenEntity)
{
$this->tokenRepository->create([
'id' => $accessTokenEntity->getIdentifier(),
'user_id' => $accessTokenEntity->getUserIdentifier(),
'client_id' => $accessTokenEntity->getClient()->getIdentifier(),
'scopes' => $this->scopesToArray($accessTokenEntity->getScopes()),
'revoked' => false,
'created_at' => new DateTime,
'updated_at' => new DateTime,
'expires_at' => $accessTokenEntity->getExpiryDateTime(),
]);
$this->events->dispatch(new AccessTokenCreated(
$accessTokenEntity->getIdentifier(),
$accessTokenEntity->getUserIdentifier(),
$accessTokenEntity->getClient()->getIdentifier()
));
}
/**
* {@inheritdoc}
*/
public function revokeAccessToken($tokenId)
{
$this->tokenRepository->revokeAccessToken($tokenId);
}
/**
* {@inheritdoc}
*/
public function isAccessTokenRevoked($tokenId)
{
return $this->tokenRepository->isAccessTokenRevoked($tokenId);
}
}
+13
View File
@@ -0,0 +1,13 @@
<?php
namespace Laravel\Passport\Bridge;
use League\OAuth2\Server\Entities\AuthCodeEntityInterface;
use League\OAuth2\Server\Entities\Traits\AuthCodeTrait;
use League\OAuth2\Server\Entities\Traits\EntityTrait;
use League\OAuth2\Server\Entities\Traits\TokenEntityTrait;
class AuthCode implements AuthCodeEntityInterface
{
use AuthCodeTrait, EntityTrait, TokenEntityTrait;
}
@@ -0,0 +1,53 @@
<?php
namespace Laravel\Passport\Bridge;
use Laravel\Passport\Passport;
use League\OAuth2\Server\Entities\AuthCodeEntityInterface;
use League\OAuth2\Server\Repositories\AuthCodeRepositoryInterface;
class AuthCodeRepository implements AuthCodeRepositoryInterface
{
use FormatsScopesForStorage;
/**
* {@inheritdoc}
*/
public function getNewAuthCode()
{
return new AuthCode;
}
/**
* {@inheritdoc}
*/
public function persistNewAuthCode(AuthCodeEntityInterface $authCodeEntity)
{
$attributes = [
'id' => $authCodeEntity->getIdentifier(),
'user_id' => $authCodeEntity->getUserIdentifier(),
'client_id' => $authCodeEntity->getClient()->getIdentifier(),
'scopes' => $this->formatScopesForStorage($authCodeEntity->getScopes()),
'revoked' => false,
'expires_at' => $authCodeEntity->getExpiryDateTime(),
];
Passport::authCode()->forceFill($attributes)->save();
}
/**
* {@inheritdoc}
*/
public function revokeAuthCode($codeId)
{
Passport::authCode()->where('id', $codeId)->update(['revoked' => true]);
}
/**
* {@inheritdoc}
*/
public function isAuthCodeRevoked($codeId)
{
return Passport::authCode()->where('id', $codeId)->where('revoked', 1)->exists();
}
}
+66
View File
@@ -0,0 +1,66 @@
<?php
namespace Laravel\Passport\Bridge;
use League\OAuth2\Server\Entities\ClientEntityInterface;
use League\OAuth2\Server\Entities\Traits\ClientTrait;
class Client implements ClientEntityInterface
{
use ClientTrait;
/**
* The client identifier.
*
* @var string
*/
protected $identifier;
/**
* The client's provider.
*
* @var string
*/
public $provider;
/**
* Create a new client instance.
*
* @param string $identifier
* @param string $name
* @param string $redirectUri
* @param bool $isConfidential
* @param string|null $provider
* @return void
*/
public function __construct($identifier, $name, $redirectUri, $isConfidential = false, $provider = null)
{
$this->setIdentifier((string) $identifier);
$this->name = $name;
$this->isConfidential = $isConfidential;
$this->redirectUri = explode(',', $redirectUri);
$this->provider = $provider;
}
/**
* Get the client's identifier.
*
* @return string
*/
public function getIdentifier()
{
return (string) $this->identifier;
}
/**
* Set the client's identifier.
*
* @param string $identifier
* @return void
*/
public function setIdentifier($identifier)
{
$this->identifier = $identifier;
}
}
@@ -0,0 +1,106 @@
<?php
namespace Laravel\Passport\Bridge;
use Laravel\Passport\ClientRepository as ClientModelRepository;
use Laravel\Passport\Passport;
use League\OAuth2\Server\Repositories\ClientRepositoryInterface;
class ClientRepository implements ClientRepositoryInterface
{
/**
* The client model repository.
*
* @var \Laravel\Passport\ClientRepository
*/
protected $clients;
/**
* Create a new repository instance.
*
* @param \Laravel\Passport\ClientRepository $clients
* @return void
*/
public function __construct(ClientModelRepository $clients)
{
$this->clients = $clients;
}
/**
* {@inheritdoc}
*/
public function getClientEntity($clientIdentifier)
{
$record = $this->clients->findActive($clientIdentifier);
if (! $record) {
return;
}
return new Client(
$clientIdentifier,
$record->name,
$record->redirect,
$record->confidential(),
$record->provider
);
}
/**
* {@inheritdoc}
*/
public function validateClient($clientIdentifier, $clientSecret, $grantType)
{
// First, we will verify that the client exists and is authorized to create personal
// access tokens. Generally personal access tokens are only generated by the user
// from the main interface. We'll only let certain clients generate the tokens.
$record = $this->clients->findActive($clientIdentifier);
if (! $record || ! $this->handlesGrant($record, $grantType)) {
return false;
}
return ! $record->confidential() || $this->verifySecret((string) $clientSecret, $record->secret);
}
/**
* Determine if the given client can handle the given grant type.
*
* @param \Laravel\Passport\Client $record
* @param string $grantType
* @return bool
*/
protected function handlesGrant($record, $grantType)
{
if (! $record->hasGrantType($grantType)) {
return false;
}
switch ($grantType) {
case 'authorization_code':
return ! $record->firstParty();
case 'personal_access':
return $record->personal_access_client && $record->confidential();
case 'password':
return $record->password_client;
case 'client_credentials':
return $record->confidential();
default:
return true;
}
}
/**
* Verify the client secret is valid.
*
* @param string $clientSecret
* @param string $storedHash
* @return bool
*/
protected function verifySecret($clientSecret, $storedHash)
{
return Passport::$hashesClientSecrets
? password_verify($clientSecret, $storedHash)
: hash_equals($storedHash, $clientSecret);
}
}
@@ -0,0 +1,30 @@
<?php
namespace Laravel\Passport\Bridge;
trait FormatsScopesForStorage
{
/**
* Format the given scopes for storage.
*
* @param array $scopes
* @return string
*/
public function formatScopesForStorage(array $scopes)
{
return json_encode($this->scopesToArray($scopes));
}
/**
* Get an array of scope identifiers for storage.
*
* @param array $scopes
* @return array
*/
public function scopesToArray(array $scopes)
{
return array_map(function ($scope) {
return $scope->getIdentifier();
}, $scopes);
}
}
@@ -0,0 +1,54 @@
<?php
namespace Laravel\Passport\Bridge;
use DateInterval;
use League\OAuth2\Server\Grant\AbstractGrant;
use League\OAuth2\Server\ResponseTypes\ResponseTypeInterface;
use Psr\Http\Message\ServerRequestInterface;
class PersonalAccessGrant extends AbstractGrant
{
/**
* {@inheritdoc}
*/
public function respondToAccessTokenRequest(
ServerRequestInterface $request,
ResponseTypeInterface $responseType,
DateInterval $accessTokenTTL
) {
// Validate request
$client = $this->validateClient($request);
$scopes = $this->validateScopes($this->getRequestParameter('scope', $request));
$userIdentifier = $this->getRequestParameter('user_id', $request);
// Finalize the requested scopes
$scopes = $this->scopeRepository->finalizeScopes(
$scopes,
$this->getIdentifier(),
$client,
$userIdentifier
);
// Issue and persist access token
$accessToken = $this->issueAccessToken(
$accessTokenTTL,
$client,
$userIdentifier,
$scopes
);
// Inject access token into response type
$responseType->setAccessToken($accessToken);
return $responseType;
}
/**
* {@inheritdoc}
*/
public function getIdentifier()
{
return 'personal_access';
}
}
@@ -0,0 +1,12 @@
<?php
namespace Laravel\Passport\Bridge;
use League\OAuth2\Server\Entities\RefreshTokenEntityInterface;
use League\OAuth2\Server\Entities\Traits\EntityTrait;
use League\OAuth2\Server\Entities\Traits\RefreshTokenTrait;
class RefreshToken implements RefreshTokenEntityInterface
{
use EntityTrait, RefreshTokenTrait;
}
@@ -0,0 +1,78 @@
<?php
namespace Laravel\Passport\Bridge;
use Illuminate\Contracts\Events\Dispatcher;
use Laravel\Passport\Events\RefreshTokenCreated;
use Laravel\Passport\RefreshTokenRepository as PassportRefreshTokenRepository;
use League\OAuth2\Server\Entities\RefreshTokenEntityInterface;
use League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface;
class RefreshTokenRepository implements RefreshTokenRepositoryInterface
{
/**
* The refresh token repository instance.
*
* @var \Illuminate\Database\Connection
*/
protected $refreshTokenRepository;
/**
* The event dispatcher instance.
*
* @var \Illuminate\Contracts\Events\Dispatcher
*/
protected $events;
/**
* Create a new repository instance.
*
* @param \Laravel\Passport\RefreshTokenRepository $refreshTokenRepository
* @param \Illuminate\Contracts\Events\Dispatcher $events
* @return void
*/
public function __construct(PassportRefreshTokenRepository $refreshTokenRepository, Dispatcher $events)
{
$this->events = $events;
$this->refreshTokenRepository = $refreshTokenRepository;
}
/**
* {@inheritdoc}
*/
public function getNewRefreshToken()
{
return new RefreshToken;
}
/**
* {@inheritdoc}
*/
public function persistNewRefreshToken(RefreshTokenEntityInterface $refreshTokenEntity)
{
$this->refreshTokenRepository->create([
'id' => $id = $refreshTokenEntity->getIdentifier(),
'access_token_id' => $accessTokenId = $refreshTokenEntity->getAccessToken()->getIdentifier(),
'revoked' => false,
'expires_at' => $refreshTokenEntity->getExpiryDateTime(),
]);
$this->events->dispatch(new RefreshTokenCreated($id, $accessTokenId));
}
/**
* {@inheritdoc}
*/
public function revokeRefreshToken($tokenId)
{
$this->refreshTokenRepository->revokeRefreshToken($tokenId);
}
/**
* {@inheritdoc}
*/
public function isRefreshTokenRevoked($tokenId)
{
return $this->refreshTokenRepository->isRefreshTokenRevoked($tokenId);
}
}
+33
View File
@@ -0,0 +1,33 @@
<?php
namespace Laravel\Passport\Bridge;
use League\OAuth2\Server\Entities\ScopeEntityInterface;
use League\OAuth2\Server\Entities\Traits\EntityTrait;
class Scope implements ScopeEntityInterface
{
use EntityTrait;
/**
* Create a new scope instance.
*
* @param string $name
* @return void
*/
public function __construct($name)
{
$this->setIdentifier($name);
}
/**
* Get the data that should be serialized to JSON.
*
* @return mixed
*/
#[\ReturnTypeWillChange]
public function jsonSerialize()
{
return $this->getIdentifier();
}
}
@@ -0,0 +1,61 @@
<?php
namespace Laravel\Passport\Bridge;
use Laravel\Passport\ClientRepository;
use Laravel\Passport\Passport;
use League\OAuth2\Server\Entities\ClientEntityInterface;
use League\OAuth2\Server\Repositories\ScopeRepositoryInterface;
class ScopeRepository implements ScopeRepositoryInterface
{
/**
* The client repository.
*
* @var \Laravel\Passport\ClientRepository|null
*/
protected ?ClientRepository $clients;
/**
* Create a new scope repository.
*
* @param \Laravel\Passport\ClientRepository|null $clients
* @return void
*/
public function __construct(?ClientRepository $clients = null)
{
$this->clients = $clients;
}
/**
* {@inheritdoc}
*/
public function getScopeEntityByIdentifier($identifier)
{
if (Passport::hasScope($identifier)) {
return new Scope($identifier);
}
}
/**
* {@inheritdoc}
*/
public function finalizeScopes(
array $scopes, $grantType,
ClientEntityInterface $clientEntity, $userIdentifier = null)
{
if (! in_array($grantType, ['password', 'personal_access', 'client_credentials'])) {
$scopes = collect($scopes)->reject(function ($scope) {
return trim($scope->getIdentifier()) === '*';
})->values()->all();
}
$client = $this->clients?->findActive($clientEntity->getIdentifier());
return collect($scopes)->filter(function ($scope) {
return Passport::hasScope($scope->getIdentifier());
})->when($client, function ($scopes, $client) {
return $scopes->filter(fn ($scope) => $client->hasScope($scope->getIdentifier()));
})->values()->all();
}
}
+22
View File
@@ -0,0 +1,22 @@
<?php
namespace Laravel\Passport\Bridge;
use League\OAuth2\Server\Entities\Traits\EntityTrait;
use League\OAuth2\Server\Entities\UserEntityInterface;
class User implements UserEntityInterface
{
use EntityTrait;
/**
* Create a new user instance.
*
* @param string|int $identifier
* @return void
*/
public function __construct($identifier)
{
$this->setIdentifier($identifier);
}
}
@@ -0,0 +1,69 @@
<?php
namespace Laravel\Passport\Bridge;
use Illuminate\Contracts\Hashing\Hasher;
use League\OAuth2\Server\Entities\ClientEntityInterface;
use League\OAuth2\Server\Repositories\UserRepositoryInterface;
use RuntimeException;
class UserRepository implements UserRepositoryInterface
{
/**
* The hasher implementation.
*
* @var \Illuminate\Contracts\Hashing\Hasher
*/
protected $hasher;
/**
* Create a new repository instance.
*
* @param \Illuminate\Contracts\Hashing\Hasher $hasher
* @return void
*/
public function __construct(Hasher $hasher)
{
$this->hasher = $hasher;
}
/**
* {@inheritdoc}
*/
public function getUserEntityByUserCredentials($username, $password, $grantType, ClientEntityInterface $clientEntity)
{
$provider = $clientEntity->provider ?: config('auth.guards.api.provider');
if (is_null($model = config('auth.providers.'.$provider.'.model'))) {
throw new RuntimeException('Unable to determine authentication model from configuration.');
}
if (method_exists($model, 'findAndValidateForPassport')) {
$user = (new $model)->findAndValidateForPassport($username, $password);
if (! $user) {
return;
}
return new User($user->getAuthIdentifier());
}
if (method_exists($model, 'findForPassport')) {
$user = (new $model)->findForPassport($username);
} else {
$user = (new $model)->where('email', $username)->first();
}
if (! $user) {
return;
} elseif (method_exists($user, 'validateForPassportPasswordGrant')) {
if (! $user->validateForPassportPasswordGrant($password)) {
return;
}
} elseif (! $this->hasher->check($password, $user->getAuthPassword())) {
return;
}
return new User($user->getAuthIdentifier());
}
}
+238
View File
@@ -0,0 +1,238 @@
<?php
namespace Laravel\Passport;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Str;
use Laravel\Passport\Database\Factories\ClientFactory;
class Client extends Model
{
use HasFactory;
use ResolvesInheritedScopes;
/**
* The database table used by the model.
*
* @var string
*/
protected $table = 'oauth_clients';
/**
* The guarded attributes on the model.
*
* @var array
*/
protected $guarded = [];
/**
* The attributes excluded from the model's JSON form.
*
* @var array
*/
protected $hidden = [
'secret',
];
/**
* The attributes that should be cast to native types.
*
* @var array
*/
protected $casts = [
'grant_types' => 'array',
'scopes' => 'array',
'personal_access_client' => 'bool',
'password_client' => 'bool',
'revoked' => 'bool',
];
/**
* The temporary plain-text client secret.
*
* @var string|null
*/
protected $plainSecret;
/**
* Bootstrap the model and its traits.
*
* @return void
*/
public static function boot()
{
parent::boot();
static::creating(function ($model) {
if (Passport::clientUuids()) {
$model->{$model->getKeyName()} = $model->{$model->getKeyName()} ?: (string) Str::orderedUuid();
}
});
}
/**
* Get the user that the client belongs to.
*
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function user()
{
$provider = $this->provider ?: config('auth.guards.api.provider');
return $this->belongsTo(
config("auth.providers.{$provider}.model")
);
}
/**
* Get all of the authentication codes for the client.
*
* @return \Illuminate\Database\Eloquent\Relations\HasMany
*/
public function authCodes()
{
return $this->hasMany(Passport::authCodeModel(), 'client_id');
}
/**
* Get all of the tokens that belong to the client.
*
* @return \Illuminate\Database\Eloquent\Relations\HasMany
*/
public function tokens()
{
return $this->hasMany(Passport::tokenModel(), 'client_id');
}
/**
* The temporary non-hashed client secret.
*
* This is only available once during the request that created the client.
*
* @return string|null
*/
public function getPlainSecretAttribute()
{
return $this->plainSecret;
}
/**
* Set the value of the secret attribute.
*
* @param string|null $value
* @return void
*/
public function setSecretAttribute($value)
{
$this->plainSecret = $value;
if (is_null($value) || ! Passport::$hashesClientSecrets) {
$this->attributes['secret'] = $value;
return;
}
$this->attributes['secret'] = password_hash($value, PASSWORD_BCRYPT);
}
/**
* Determine if the client is a "first party" client.
*
* @return bool
*/
public function firstParty()
{
return $this->personal_access_client || $this->password_client;
}
/**
* Determine if the client should skip the authorization prompt.
*
* @return bool
*/
public function skipsAuthorization()
{
return false;
}
/**
* Determine if the client has the given grant type.
*
* @param string $grantType
* @return bool
*/
public function hasGrantType($grantType)
{
if (! isset($this->attributes['grant_types']) || ! is_array($this->grant_types)) {
return true;
}
return in_array($grantType, $this->grant_types);
}
/**
* Determine whether the client has the given scope.
*
* @param string $scope
* @return bool
*/
public function hasScope($scope)
{
if (! isset($this->attributes['scopes']) || ! is_array($this->scopes)) {
return true;
}
$scopes = Passport::$withInheritedScopes
? $this->resolveInheritedScopes($scope)
: [$scope];
foreach ($scopes as $scope) {
if (in_array($scope, $this->scopes)) {
return true;
}
}
return false;
}
/**
* Determine if the client is a confidential client.
*
* @return bool
*/
public function confidential()
{
return ! empty($this->secret);
}
/**
* Get the auto-incrementing key type.
*
* @return string
*/
public function getKeyType()
{
return Passport::clientUuids() ? 'string' : $this->keyType;
}
/**
* Get the value indicating whether the IDs are incrementing.
*
* @return bool
*/
public function getIncrementing()
{
return Passport::clientUuids() ? false : $this->incrementing;
}
/**
* Create a new factory instance for the model.
*
* @return \Illuminate\Database\Eloquent\Factories\Factory
*/
public static function newFactory()
{
return ClientFactory::new();
}
}
+266
View File
@@ -0,0 +1,266 @@
<?php
namespace Laravel\Passport;
use Illuminate\Support\Str;
use RuntimeException;
class ClientRepository
{
/**
* The personal access client ID.
*
* @var int|string|null
*/
protected $personalAccessClientId;
/**
* The personal access client secret.
*
* @var string|null
*/
protected $personalAccessClientSecret;
/**
* Create a new client repository.
*
* @param int|string|null $personalAccessClientId
* @param string|null $personalAccessClientSecret
* @return void
*/
public function __construct($personalAccessClientId = null, $personalAccessClientSecret = null)
{
$this->personalAccessClientId = $personalAccessClientId;
$this->personalAccessClientSecret = $personalAccessClientSecret;
}
/**
* Get a client by the given ID.
*
* @param int|string $id
* @return \Laravel\Passport\Client|null
*/
public function find($id)
{
$client = Passport::client();
return $client->where($client->getKeyName(), $id)->first();
}
/**
* Get an active client by the given ID.
*
* @param int|string $id
* @return \Laravel\Passport\Client|null
*/
public function findActive($id)
{
$client = $this->find($id);
return $client && ! $client->revoked ? $client : null;
}
/**
* Get a client instance for the given ID and user ID.
*
* @param int|string $clientId
* @param mixed $userId
* @return \Laravel\Passport\Client|null
*/
public function findForUser($clientId, $userId)
{
$client = Passport::client();
return $client
->where($client->getKeyName(), $clientId)
->where('user_id', $userId)
->first();
}
/**
* Get the client instances for the given user ID.
*
* @param mixed $userId
* @return \Illuminate\Database\Eloquent\Collection
*/
public function forUser($userId)
{
return Passport::client()
->where('user_id', $userId)
->orderBy('name', 'asc')->get();
}
/**
* Get the active client instances for the given user ID.
*
* @param mixed $userId
* @return \Illuminate\Database\Eloquent\Collection
*/
public function activeForUser($userId)
{
return $this->forUser($userId)->reject(function ($client) {
return $client->revoked;
})->values();
}
/**
* Get the personal access token client for the application.
*
* @return \Laravel\Passport\Client
*
* @throws \RuntimeException
*/
public function personalAccessClient()
{
if ($this->personalAccessClientId) {
return $this->find($this->personalAccessClientId);
}
$client = Passport::personalAccessClient();
if (! $client->exists()) {
throw new RuntimeException('Personal access client not found. Please create one.');
}
return $client->orderBy($client->getKeyName(), 'desc')->first()->client;
}
/**
* Store a new client.
*
* @param int|null $userId
* @param string $name
* @param string $redirect
* @param string|null $provider
* @param bool $personalAccess
* @param bool $password
* @param bool $confidential
* @return \Laravel\Passport\Client
*/
public function create($userId, $name, $redirect, $provider = null, $personalAccess = false, $password = false, $confidential = true)
{
$client = Passport::client()->forceFill([
'user_id' => $userId,
'name' => $name,
'secret' => ($confidential || $personalAccess) ? Str::random(40) : null,
'provider' => $provider,
'redirect' => $redirect,
'personal_access_client' => $personalAccess,
'password_client' => $password,
'revoked' => false,
]);
$client->save();
return $client;
}
/**
* Store a new personal access token client.
*
* @param int|null $userId
* @param string $name
* @param string $redirect
* @return \Laravel\Passport\Client
*/
public function createPersonalAccessClient($userId, $name, $redirect)
{
return tap($this->create($userId, $name, $redirect, null, true), function ($client) {
$accessClient = Passport::personalAccessClient();
$accessClient->client_id = $client->getKey();
$accessClient->save();
});
}
/**
* Store a new password grant client.
*
* @param int|null $userId
* @param string $name
* @param string $redirect
* @param string|null $provider
* @return \Laravel\Passport\Client
*/
public function createPasswordGrantClient($userId, $name, $redirect, $provider = null)
{
return $this->create($userId, $name, $redirect, $provider, false, true);
}
/**
* Update the given client.
*
* @param \Laravel\Passport\Client $client
* @param string $name
* @param string $redirect
* @return \Laravel\Passport\Client
*/
public function update(Client $client, $name, $redirect)
{
$client->forceFill([
'name' => $name, 'redirect' => $redirect,
])->save();
return $client;
}
/**
* Regenerate the client secret.
*
* @param \Laravel\Passport\Client $client
* @return \Laravel\Passport\Client
*/
public function regenerateSecret(Client $client)
{
$client->forceFill([
'secret' => Str::random(40),
])->save();
return $client;
}
/**
* Determine if the given client is revoked.
*
* @param int|string $id
* @return bool
*/
public function revoked($id)
{
$client = $this->find($id);
return is_null($client) || $client->revoked;
}
/**
* Delete the given client.
*
* @param \Laravel\Passport\Client $client
* @return void
*/
public function delete(Client $client)
{
$client->tokens()->update(['revoked' => true]);
$client->forceFill(['revoked' => true])->save();
}
/**
* Get the personal access client id.
*
* @return int|string|null
*/
public function getPersonalAccessClientId()
{
return $this->personalAccessClientId;
}
/**
* Get the personal access client secret.
*
* @return string|null
*/
public function getPersonalAccessClientSecret()
{
return $this->personalAccessClientSecret;
}
}
@@ -0,0 +1,173 @@
<?php
namespace Laravel\Passport\Console;
use Illuminate\Console\Command;
use Laravel\Passport\Client;
use Laravel\Passport\ClientRepository;
use Laravel\Passport\Passport;
class ClientCommand extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'passport:client
{--personal : Create a personal access token client}
{--password : Create a password grant client}
{--client : Create a client credentials grant client}
{--name= : The name of the client}
{--provider= : The name of the user provider}
{--redirect_uri= : The URI to redirect to after authorization }
{--user_id= : The user ID the client should be assigned to }
{--public : Create a public client (Auth code grant type only) }';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Create a client for issuing access tokens';
/**
* Execute the console command.
*
* @param \Laravel\Passport\ClientRepository $clients
* @return void
*/
public function handle(ClientRepository $clients)
{
if ($this->option('personal')) {
$this->createPersonalClient($clients);
} elseif ($this->option('password')) {
$this->createPasswordClient($clients);
} elseif ($this->option('client')) {
$this->createClientCredentialsClient($clients);
} else {
$this->createAuthCodeClient($clients);
}
}
/**
* Create a new personal access client.
*
* @param \Laravel\Passport\ClientRepository $clients
* @return void
*/
protected function createPersonalClient(ClientRepository $clients)
{
$name = $this->option('name') ?: $this->ask(
'What should we name the personal access client?',
config('app.name').' Personal Access Client'
);
$client = $clients->createPersonalAccessClient(
null, $name, 'http://localhost'
);
$this->info('Personal access client created successfully.');
$this->outputClientDetails($client);
}
/**
* Create a new password grant client.
*
* @param \Laravel\Passport\ClientRepository $clients
* @return void
*/
protected function createPasswordClient(ClientRepository $clients)
{
$name = $this->option('name') ?: $this->ask(
'What should we name the password grant client?',
config('app.name').' Password Grant Client'
);
$providers = array_keys(config('auth.providers'));
$provider = $this->option('provider') ?: $this->choice(
'Which user provider should this client use to retrieve users?',
$providers,
in_array('users', $providers) ? 'users' : null
);
$client = $clients->createPasswordGrantClient(
null, $name, 'http://localhost', $provider
);
$this->info('Password grant client created successfully.');
$this->outputClientDetails($client);
}
/**
* Create a client credentials grant client.
*
* @param \Laravel\Passport\ClientRepository $clients
* @return void
*/
protected function createClientCredentialsClient(ClientRepository $clients)
{
$name = $this->option('name') ?: $this->ask(
'What should we name the client?',
config('app.name').' ClientCredentials Grant Client'
);
$client = $clients->create(
null, $name, ''
);
$this->info('New client created successfully.');
$this->outputClientDetails($client);
}
/**
* Create a authorization code client.
*
* @param \Laravel\Passport\ClientRepository $clients
* @return void
*/
protected function createAuthCodeClient(ClientRepository $clients)
{
$userId = $this->option('user_id') ?: $this->ask(
'Which user ID should the client be assigned to? (Optional)'
);
$name = $this->option('name') ?: $this->ask(
'What should we name the client?'
);
$redirect = $this->option('redirect_uri') ?: $this->ask(
'Where should we redirect the request after authorization?',
url('/auth/callback')
);
$client = $clients->create(
$userId, $name, $redirect, null, false, false, ! $this->option('public')
);
$this->info('New client created successfully.');
$this->outputClientDetails($client);
}
/**
* Output the client's ID and secret key.
*
* @param \Laravel\Passport\Client $client
* @return void
*/
protected function outputClientDetails(Client $client)
{
if (Passport::$hashesClientSecrets) {
$this->line('<comment>Here is your new client secret. This is the only time it will be shown so don\'t lose it!</comment>');
$this->line('');
}
$this->line('<comment>Client ID:</comment> '.$client->getKey());
$this->line('<comment>Client secret:</comment> '.$client->plainSecret);
}
}
@@ -0,0 +1,55 @@
<?php
namespace Laravel\Passport\Console;
use Illuminate\Console\Command;
use Laravel\Passport\Passport;
class HashCommand extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'passport:hash {--force : Force the operation to run without confirmation prompt}';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Hash all of the existing secrets in the clients table';
/**
* Execute the console command.
*
* @return void
*/
public function handle()
{
if (! Passport::$hashesClientSecrets) {
$this->warn('Please enable client hashing yet in your AppServiceProvider before continuing.');
return;
}
if ($this->option('force') || $this->confirm('Are you sure you want to hash all client secrets? This cannot be undone.')) {
$model = Passport::clientModel();
foreach ((new $model)->whereNotNull('secret')->cursor() as $client) {
if (password_get_info($client->secret)['algo'] === PASSWORD_BCRYPT) {
continue;
}
$client->timestamps = false;
$client->forceFill([
'secret' => $client->secret,
])->save();
}
$this->info('All client secrets were successfully hashed.');
}
}
}
@@ -0,0 +1,87 @@
<?php
namespace Laravel\Passport\Console;
use Illuminate\Console\Command;
use Laravel\Passport\Passport;
class InstallCommand extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'passport:install
{--uuids : Use UUIDs for all client IDs}
{--force : Overwrite keys they already exist}
{--length=4096 : The length of the private key}';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Run the commands necessary to prepare Passport for use';
/**
* Execute the console command.
*
* @return void
*/
public function handle()
{
$provider = in_array('users', array_keys(config('auth.providers'))) ? 'users' : null;
$this->call('passport:keys', ['--force' => $this->option('force'), '--length' => $this->option('length')]);
if ($this->option('uuids')) {
$this->configureUuids();
}
$this->call('passport:client', ['--personal' => true, '--name' => config('app.name').' Personal Access Client']);
$this->call('passport:client', ['--password' => true, '--name' => config('app.name').' Password Grant Client', '--provider' => $provider]);
}
/**
* Configure Passport for client UUIDs.
*
* @return void
*/
protected function configureUuids()
{
$this->call('vendor:publish', ['--tag' => 'passport-config']);
$this->call('vendor:publish', ['--tag' => 'passport-migrations']);
config(['passport.client_uuids' => true]);
Passport::setClientUuids(true);
$this->replaceInFile(config_path('passport.php'), '\'client_uuids\' => false', '\'client_uuids\' => true');
$this->replaceInFile(database_path('migrations/2016_06_01_000001_create_oauth_auth_codes_table.php'), '$table->unsignedBigInteger(\'client_id\');', '$table->uuid(\'client_id\');');
$this->replaceInFile(database_path('migrations/2016_06_01_000002_create_oauth_access_tokens_table.php'), '$table->unsignedBigInteger(\'client_id\');', '$table->uuid(\'client_id\');');
$this->replaceInFile(database_path('migrations/2016_06_01_000004_create_oauth_clients_table.php'), '$table->bigIncrements(\'id\');', '$table->uuid(\'id\')->primary();');
$this->replaceInFile(database_path('migrations/2016_06_01_000005_create_oauth_personal_access_clients_table.php'), '$table->unsignedBigInteger(\'client_id\');', '$table->uuid(\'client_id\');');
if ($this->confirm('In order to finish configuring client UUIDs, we need to rebuild the Passport database tables. Would you like to rollback and re-run your last migration?')) {
$this->call('migrate:rollback');
$this->call('migrate');
$this->line('');
}
}
/**
* Replace a given string in a given file.
*
* @param string $path
* @param string $search
* @param string $replace
* @return void
*/
protected function replaceInFile($path, $search, $replace)
{
file_put_contents(
$path,
str_replace($search, $replace, file_get_contents($path))
);
}
}
@@ -0,0 +1,63 @@
<?php
namespace Laravel\Passport\Console;
use Illuminate\Console\Command;
use Illuminate\Support\Arr;
use Laravel\Passport\Passport;
use phpseclib\Crypt\RSA as LegacyRSA;
use phpseclib3\Crypt\RSA;
class KeysCommand extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'passport:keys
{--force : Overwrite keys they already exist}
{--length=4096 : The length of the private key}';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Create the encryption keys for API authentication';
/**
* Execute the console command.
*
* @return int
*/
public function handle()
{
[$publicKey, $privateKey] = [
Passport::keyPath('oauth-public.key'),
Passport::keyPath('oauth-private.key'),
];
if ((file_exists($publicKey) || file_exists($privateKey)) && ! $this->option('force')) {
$this->error('Encryption keys already exist. Use the --force option to overwrite them.');
return 1;
} else {
if (class_exists(LegacyRSA::class)) {
$keys = (new LegacyRSA)->createKey($this->input ? (int) $this->option('length') : 4096);
file_put_contents($publicKey, Arr::get($keys, 'publickey'));
file_put_contents($privateKey, Arr::get($keys, 'privatekey'));
} else {
$key = RSA::createKey($this->input ? (int) $this->option('length') : 4096);
file_put_contents($publicKey, (string) $key->getPublicKey());
file_put_contents($privateKey, (string) $key);
}
$this->info('Encryption keys generated successfully.');
}
return 0;
}
}
@@ -0,0 +1,62 @@
<?php
namespace Laravel\Passport\Console;
use Illuminate\Console\Command;
use Illuminate\Support\Carbon;
use Laravel\Passport\Passport;
class PurgeCommand extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'passport:purge
{--revoked : Only purge revoked tokens and authentication codes}
{--expired : Only purge expired tokens and authentication codes}
{--hours= : The number of hours to retain expired tokens}';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Purge revoked and / or expired tokens and authentication codes';
/**
* Execute the console command.
*/
public function handle()
{
$expired = $this->option('hours')
? Carbon::now()->subHours($this->option('hours'))
: Carbon::now()->subDays(7);
if (($this->option('revoked') && $this->option('expired')) ||
(! $this->option('revoked') && ! $this->option('expired'))) {
Passport::token()->where('revoked', 1)->orWhereDate('expires_at', '<', $expired)->delete();
Passport::authCode()->where('revoked', 1)->orWhereDate('expires_at', '<', $expired)->delete();
Passport::refreshToken()->where('revoked', 1)->orWhereDate('expires_at', '<', $expired)->delete();
$this->option('hours')
? $this->info('Purged revoked items and items expired for more than '.$this->option('hours').' hours.')
: $this->info('Purged revoked items and items expired for more than seven days.');
} elseif ($this->option('revoked')) {
Passport::token()->where('revoked', 1)->delete();
Passport::authCode()->where('revoked', 1)->delete();
Passport::refreshToken()->where('revoked', 1)->delete();
$this->info('Purged revoked items.');
} elseif ($this->option('expired')) {
Passport::token()->whereDate('expires_at', '<', $expired)->delete();
Passport::authCode()->whereDate('expires_at', '<', $expired)->delete();
Passport::refreshToken()->whereDate('expires_at', '<', $expired)->delete();
$this->option('hours')
? $this->info('Purged items expired for more than '.$this->option('hours').' hours.')
: $this->info('Purged items expired for more than seven days.');
}
}
}
@@ -0,0 +1,16 @@
<?php
namespace Laravel\Passport\Contracts;
use Illuminate\Contracts\Support\Responsable;
interface AuthorizationViewResponse extends Responsable
{
/**
* Specify the parameters that should be passed to the view.
*
* @param array $parameters
* @return $this
*/
public function withParameters($parameters = []);
}
@@ -0,0 +1,42 @@
<?php
namespace Laravel\Passport\Events;
class AccessTokenCreated
{
/**
* The newly created token ID.
*
* @var string
*/
public $tokenId;
/**
* The ID of the user associated with the token.
*
* @var string
*/
public $userId;
/**
* The ID of the client associated with the token.
*
* @var string
*/
public $clientId;
/**
* Create a new event instance.
*
* @param string $tokenId
* @param string|int|null $userId
* @param string $clientId
* @return void
*/
public function __construct($tokenId, $userId, $clientId)
{
$this->userId = $userId;
$this->tokenId = $tokenId;
$this->clientId = $clientId;
}
}
@@ -0,0 +1,33 @@
<?php
namespace Laravel\Passport\Events;
class RefreshTokenCreated
{
/**
* The newly created refresh token ID.
*
* @var string
*/
public $refreshTokenId;
/**
* The access token ID.
*
* @var string
*/
public $accessTokenId;
/**
* Create a new event instance.
*
* @param string $refreshTokenId
* @param string $accessTokenId
* @return void
*/
public function __construct($refreshTokenId, $accessTokenId)
{
$this->accessTokenId = $accessTokenId;
$this->refreshTokenId = $refreshTokenId;
}
}
@@ -0,0 +1,9 @@
<?php
namespace Laravel\Passport\Exceptions;
use Illuminate\Auth\AuthenticationException as Exception;
class AuthenticationException extends Exception
{
}
@@ -0,0 +1,18 @@
<?php
namespace Laravel\Passport\Exceptions;
use Illuminate\Auth\Access\AuthorizationException;
class InvalidAuthTokenException extends AuthorizationException
{
/**
* Create a new InvalidAuthTokenException for different auth tokens.
*
* @return static
*/
public static function different()
{
return new static('The provided auth token for the request is different from the session auth token.');
}
}
@@ -0,0 +1,40 @@
<?php
namespace Laravel\Passport\Exceptions;
use Illuminate\Auth\Access\AuthorizationException;
use Illuminate\Support\Arr;
class MissingScopeException extends AuthorizationException
{
/**
* The scopes that the user did not have.
*
* @var array
*/
protected $scopes;
/**
* Create a new missing scope exception.
*
* @param array|string $scopes
* @param string $message
* @return void
*/
public function __construct($scopes = [], $message = 'Invalid scope(s) provided.')
{
parent::__construct($message);
$this->scopes = Arr::wrap($scopes);
}
/**
* Get the scopes that the user did not have.
*
* @return array
*/
public function scopes()
{
return $this->scopes;
}
}
@@ -0,0 +1,52 @@
<?php
namespace Laravel\Passport\Exceptions;
use Exception;
use Illuminate\Http\Response;
use League\OAuth2\Server\Exception\OAuthServerException as LeagueException;
class OAuthServerException extends Exception
{
/**
* The response to render.
*
* @var \Illuminate\Http\Response
*/
protected $response;
/**
* Create a new OAuthServerException.
*
* @param \League\OAuth2\Server\Exception\OAuthServerException $e
* @param \Illuminate\Http\Response $response
* @return void
*/
public function __construct(LeagueException $e, Response $response)
{
parent::__construct($e->getMessage(), $e->getCode(), $e);
$this->response = $response;
}
/**
* Render the exception into an HTTP response.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function render($request)
{
return $this->response;
}
/**
* Get the HTTP response status code.
*
* @return int
*/
public function statusCode()
{
return $this->response->getStatusCode();
}
}
+374
View File
@@ -0,0 +1,374 @@
<?php
namespace Laravel\Passport\Guards;
use Exception;
use Firebase\JWT\JWT;
use Firebase\JWT\Key;
use Illuminate\Auth\GuardHelpers;
use Illuminate\Container\Container;
use Illuminate\Contracts\Auth\Guard;
use Illuminate\Contracts\Debug\ExceptionHandler;
use Illuminate\Contracts\Encryption\Encrypter;
use Illuminate\Cookie\CookieValuePrefix;
use Illuminate\Cookie\Middleware\EncryptCookies;
use Illuminate\Http\Request;
use Illuminate\Support\Traits\Macroable;
use Laravel\Passport\Client;
use Laravel\Passport\ClientRepository;
use Laravel\Passport\Passport;
use Laravel\Passport\PassportUserProvider;
use Laravel\Passport\TokenRepository;
use Laravel\Passport\TransientToken;
use League\OAuth2\Server\Exception\OAuthServerException;
use League\OAuth2\Server\ResourceServer;
use Nyholm\Psr7\Factory\Psr17Factory;
use Symfony\Bridge\PsrHttpMessage\Factory\PsrHttpFactory;
class TokenGuard implements Guard
{
use GuardHelpers, Macroable;
/**
* The resource server instance.
*
* @var \League\OAuth2\Server\ResourceServer
*/
protected $server;
/**
* The user provider implementation.
*
* @var \Laravel\Passport\PassportUserProvider
*/
protected $provider;
/**
* The token repository instance.
*
* @var \Laravel\Passport\TokenRepository
*/
protected $tokens;
/**
* The client repository instance.
*
* @var \Laravel\Passport\ClientRepository
*/
protected $clients;
/**
* The encrypter implementation.
*
* @var \Illuminate\Contracts\Encryption\Encrypter
*/
protected $encrypter;
/**
* The request instance.
*
* @var \Illuminate\Http\Request
*/
protected $request;
/**
* The currently authenticated client.
*
* @var \Laravel\Passport\Client|null
*/
protected $client;
/**
* Create a new token guard instance.
*
* @param \League\OAuth2\Server\ResourceServer $server
* @param \Laravel\Passport\PassportUserProvider $provider
* @param \Laravel\Passport\TokenRepository $tokens
* @param \Laravel\Passport\ClientRepository $clients
* @param \Illuminate\Contracts\Encryption\Encrypter $encrypter
* @param \Illuminate\Http\Request $request
* @return void
*/
public function __construct(
ResourceServer $server,
PassportUserProvider $provider,
TokenRepository $tokens,
ClientRepository $clients,
Encrypter $encrypter,
Request $request
) {
$this->server = $server;
$this->tokens = $tokens;
$this->clients = $clients;
$this->provider = $provider;
$this->encrypter = $encrypter;
$this->request = $request;
}
/**
* Get the user for the incoming request.
*
* @return mixed
*/
public function user()
{
if (! is_null($this->user)) {
return $this->user;
}
if ($this->request->bearerToken()) {
return $this->user = $this->authenticateViaBearerToken($this->request);
} elseif ($this->request->cookie(Passport::cookie())) {
return $this->user = $this->authenticateViaCookie($this->request);
}
}
/**
* Validate a user's credentials.
*
* @param array $credentials
* @return bool
*/
public function validate(array $credentials = [])
{
return ! is_null((new static(
$this->server,
$this->provider,
$this->tokens,
$this->clients,
$this->encrypter,
$credentials['request'],
))->user());
}
/**
* Get the client for the incoming request.
*
* @return \Laravel\Passport\Client|null
*/
public function client()
{
if (! is_null($this->client)) {
return $this->client;
}
if ($this->request->bearerToken()) {
if (! $psr = $this->getPsrRequestViaBearerToken($this->request)) {
return;
}
return $this->client = $this->clients->findActive(
$psr->getAttribute('oauth_client_id')
);
} elseif ($this->request->cookie(Passport::cookie())) {
if ($token = $this->getTokenViaCookie($this->request)) {
return $this->client = $this->clients->findActive($token['aud']);
}
}
}
/**
* Authenticate the incoming request via the Bearer token.
*
* @param \Illuminate\Http\Request $request
* @return mixed
*/
protected function authenticateViaBearerToken($request)
{
if (! $psr = $this->getPsrRequestViaBearerToken($request)) {
return;
}
$client = $this->clients->findActive(
$psr->getAttribute('oauth_client_id')
);
if (! $client ||
($client->provider &&
$client->provider !== $this->provider->getProviderName())) {
return;
}
// If the access token is valid we will retrieve the user according to the user ID
// associated with the token. We will use the provider implementation which may
// be used to retrieve users from Eloquent. Next, we'll be ready to continue.
$user = $this->provider->retrieveById(
$psr->getAttribute('oauth_user_id') ?: null
);
if (! $user) {
return;
}
// Next, we will assign a token instance to this user which the developers may use
// to determine if the token has a given scope, etc. This will be useful during
// authorization such as within the developer's Laravel model policy classes.
$token = $this->tokens->find(
$psr->getAttribute('oauth_access_token_id')
);
return $token ? $user->withAccessToken($token) : null;
}
/**
* Authenticate and get the incoming PSR-7 request via the Bearer token.
*
* @param \Illuminate\Http\Request $request
* @return \Psr\Http\Message\ServerRequestInterface|null
*/
protected function getPsrRequestViaBearerToken($request)
{
// First, we will convert the Symfony request to a PSR-7 implementation which will
// be compatible with the base OAuth2 library. The Symfony bridge can perform a
// conversion for us to a new Nyholm implementation of this PSR-7 request.
$psr = (new PsrHttpFactory(
new Psr17Factory,
new Psr17Factory,
new Psr17Factory,
new Psr17Factory
))->createRequest($request);
try {
return $this->server->validateAuthenticatedRequest($psr);
} catch (OAuthServerException $e) {
$request->headers->set('Authorization', '', true);
Container::getInstance()->make(
ExceptionHandler::class
)->report($e);
}
}
/**
* Authenticate the incoming request via the token cookie.
*
* @param \Illuminate\Http\Request $request
* @return mixed
*/
protected function authenticateViaCookie($request)
{
if (! $token = $this->getTokenViaCookie($request)) {
return;
}
// If this user exists, we will return this user and attach a "transient" token to
// the user model. The transient token assumes it has all scopes since the user
// is physically logged into the application via the application's interface.
if ($user = $this->provider->retrieveById($token['sub'])) {
return $user->withAccessToken(new TransientToken);
}
}
/**
* Get the token cookie via the incoming request.
*
* @param \Illuminate\Http\Request $request
* @return mixed
*/
protected function getTokenViaCookie($request)
{
// If we need to retrieve the token from the cookie, it'll be encrypted so we must
// first decrypt the cookie and then attempt to find the token value within the
// database. If we can't decrypt the value we'll bail out with a null return.
try {
$token = $this->decodeJwtTokenCookie($request);
} catch (Exception $e) {
return;
}
// We will compare the CSRF token in the decoded API token against the CSRF header
// sent with the request. If they don't match then this request isn't sent from
// a valid source and we won't authenticate the request for further handling.
if (! Passport::$ignoreCsrfToken && (! $this->validCsrf($token, $request) ||
time() >= $token['expiry'])) {
return;
}
return $token;
}
/**
* Decode and decrypt the JWT token cookie.
*
* @param \Illuminate\Http\Request $request
* @return array
*/
protected function decodeJwtTokenCookie($request)
{
$jwt = $request->cookie(Passport::cookie());
return (array) JWT::decode(
Passport::$decryptsCookies
? CookieValuePrefix::remove($this->encrypter->decrypt($jwt, Passport::$unserializesCookies))
: $jwt,
new Key(Passport::tokenEncryptionKey($this->encrypter), 'HS256')
);
}
/**
* Determine if the CSRF / header are valid and match.
*
* @param array $token
* @param \Illuminate\Http\Request $request
* @return bool
*/
protected function validCsrf($token, $request)
{
return isset($token['csrf']) && hash_equals(
$token['csrf'], (string) $this->getTokenFromRequest($request)
);
}
/**
* Get the CSRF token from the request.
*
* @param \Illuminate\Http\Request $request
* @return string
*/
protected function getTokenFromRequest($request)
{
$token = $request->header('X-CSRF-TOKEN');
if (! $token && $header = $request->header('X-XSRF-TOKEN')) {
$token = CookieValuePrefix::remove($this->encrypter->decrypt($header, static::serialized()));
}
return $token;
}
/**
* Set the current request instance.
*
* @param \Illuminate\Http\Request $request
* @return $this
*/
public function setRequest(Request $request)
{
$this->request = $request;
return $this;
}
/**
* Determine if the cookie contents should be serialized.
*
* @return bool
*/
public static function serialized()
{
return EncryptCookies::serialized('XSRF-TOKEN');
}
/**
* Set the client for the current request.
*
* @param \Laravel\Passport\Client $client
* @return $this
*/
public function setClient(Client $client)
{
$this->client = $client;
return $this;
}
}
+83
View File
@@ -0,0 +1,83 @@
<?php
namespace Laravel\Passport;
use Illuminate\Container\Container;
trait HasApiTokens
{
/**
* The current access token for the authentication user.
*
* @var \Laravel\Passport\Token|\Laravel\Passport\TransientToken|null
*/
protected $accessToken;
/**
* Get all of the user's registered OAuth clients.
*
* @return \Illuminate\Database\Eloquent\Relations\HasMany
*/
public function clients()
{
return $this->hasMany(Passport::clientModel(), 'user_id');
}
/**
* Get all of the access tokens for the user.
*
* @return \Illuminate\Database\Eloquent\Relations\HasMany
*/
public function tokens()
{
return $this->hasMany(Passport::tokenModel(), 'user_id')->orderBy('created_at', 'desc');
}
/**
* Get the current access token being used by the user.
*
* @return \Laravel\Passport\Token|\Laravel\Passport\TransientToken|null
*/
public function token()
{
return $this->accessToken;
}
/**
* Determine if the current API token has a given scope.
*
* @param string $scope
* @return bool
*/
public function tokenCan($scope)
{
return $this->accessToken ? $this->accessToken->can($scope) : false;
}
/**
* Create a new personal access token for the user.
*
* @param string $name
* @param array $scopes
* @return \Laravel\Passport\PersonalAccessTokenResult
*/
public function createToken($name, array $scopes = [])
{
return Container::getInstance()->make(PersonalAccessTokenFactory::class)->make(
$this->getKey(), $name, $scopes
);
}
/**
* Set the current access token for the user.
*
* @param \Laravel\Passport\Token|\Laravel\Passport\TransientToken|null $accessToken
* @return $this
*/
public function withAccessToken($accessToken)
{
$this->accessToken = $accessToken;
return $this;
}
}
@@ -0,0 +1,56 @@
<?php
namespace Laravel\Passport\Http\Controllers;
use Laravel\Passport\TokenRepository;
use League\OAuth2\Server\AuthorizationServer;
use Nyholm\Psr7\Response as Psr7Response;
use Psr\Http\Message\ServerRequestInterface;
class AccessTokenController
{
use HandlesOAuthErrors;
/**
* The authorization server.
*
* @var \League\OAuth2\Server\AuthorizationServer
*/
protected $server;
/**
* The token repository instance.
*
* @var \Laravel\Passport\TokenRepository
*/
protected $tokens;
/**
* Create a new controller instance.
*
* @param \League\OAuth2\Server\AuthorizationServer $server
* @param \Laravel\Passport\TokenRepository $tokens
* @return void
*/
public function __construct(AuthorizationServer $server,
TokenRepository $tokens)
{
$this->server = $server;
$this->tokens = $tokens;
}
/**
* Authorize a client to access the user's account.
*
* @param \Psr\Http\Message\ServerRequestInterface $request
* @return \Illuminate\Http\Response
*/
public function issueToken(ServerRequestInterface $request)
{
return $this->withErrorHandling(function () use ($request) {
return $this->convertResponse(
$this->server->respondToAccessTokenRequest($request, new Psr7Response)
);
});
}
}
@@ -0,0 +1,51 @@
<?php
namespace Laravel\Passport\Http\Controllers;
use Illuminate\Http\Request;
use League\OAuth2\Server\AuthorizationServer;
use Nyholm\Psr7\Response as Psr7Response;
class ApproveAuthorizationController
{
use ConvertsPsrResponses, HandlesOAuthErrors, RetrievesAuthRequestFromSession;
/**
* The authorization server.
*
* @var \League\OAuth2\Server\AuthorizationServer
*/
protected $server;
/**
* Create a new controller instance.
*
* @param \League\OAuth2\Server\AuthorizationServer $server
* @return void
*/
public function __construct(AuthorizationServer $server)
{
$this->server = $server;
}
/**
* Approve the authorization request.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function approve(Request $request)
{
$this->assertValidAuthToken($request);
$authRequest = $this->getAuthRequestFromSession($request);
$authRequest->setAuthorizationApproved(true);
return $this->withErrorHandling(function () use ($authRequest) {
return $this->convertResponse(
$this->server->completeAuthorizationRequest($authRequest, new Psr7Response)
);
});
}
}
@@ -0,0 +1,220 @@
<?php
namespace Laravel\Passport\Http\Controllers;
use Illuminate\Contracts\Auth\StatefulGuard;
use Illuminate\Http\Request;
use Illuminate\Support\Str;
use Laravel\Passport\Bridge\User;
use Laravel\Passport\ClientRepository;
use Laravel\Passport\Contracts\AuthorizationViewResponse;
use Laravel\Passport\Exceptions\AuthenticationException;
use Laravel\Passport\Passport;
use Laravel\Passport\TokenRepository;
use League\OAuth2\Server\AuthorizationServer;
use League\OAuth2\Server\Exception\OAuthServerException;
use Nyholm\Psr7\Response as Psr7Response;
use Psr\Http\Message\ServerRequestInterface;
class AuthorizationController
{
use HandlesOAuthErrors;
/**
* The authorization server.
*
* @var \League\OAuth2\Server\AuthorizationServer
*/
protected $server;
/**
* The guard implementation.
*
* @var \Illuminate\Contracts\Auth\StatefulGuard
*/
protected $guard;
/**
* The authorization view response implementation.
*
* @var \Laravel\Passport\Contracts\AuthorizationViewResponse
*/
protected $response;
/**
* Create a new controller instance.
*
* @param \League\OAuth2\Server\AuthorizationServer $server
* @param \Illuminate\Contracts\Auth\StatefulGuard $guard
* @param \Laravel\Passport\Contracts\AuthorizationViewResponse $response
* @return void
*/
public function __construct(AuthorizationServer $server,
StatefulGuard $guard,
AuthorizationViewResponse $response)
{
$this->server = $server;
$this->guard = $guard;
$this->response = $response;
}
/**
* Authorize a client to access the user's account.
*
* @param \Psr\Http\Message\ServerRequestInterface $psrRequest
* @param \Illuminate\Http\Request $request
* @param \Laravel\Passport\ClientRepository $clients
* @param \Laravel\Passport\TokenRepository $tokens
* @return \Illuminate\Http\Response|\Laravel\Passport\Contracts\AuthorizationViewResponse
*/
public function authorize(ServerRequestInterface $psrRequest,
Request $request,
ClientRepository $clients,
TokenRepository $tokens)
{
$authRequest = $this->withErrorHandling(function () use ($psrRequest) {
return $this->server->validateAuthorizationRequest($psrRequest);
});
if ($this->guard->guest()) {
return $request->get('prompt') === 'none'
? $this->denyRequest($authRequest)
: $this->promptForLogin($request);
}
if ($request->get('prompt') === 'login' &&
! $request->session()->get('promptedForLogin', false)) {
$this->guard->logout();
$request->session()->invalidate();
$request->session()->regenerateToken();
return $this->promptForLogin($request);
}
$request->session()->forget('promptedForLogin');
$scopes = $this->parseScopes($authRequest);
$user = $this->guard->user();
$client = $clients->find($authRequest->getClient()->getIdentifier());
if ($request->get('prompt') !== 'consent' &&
($client->skipsAuthorization() || $this->hasValidToken($tokens, $user, $client, $scopes))) {
return $this->approveRequest($authRequest, $user);
}
if ($request->get('prompt') === 'none') {
return $this->denyRequest($authRequest, $user);
}
$request->session()->put('authToken', $authToken = Str::random());
$request->session()->put('authRequest', $authRequest);
return $this->response->withParameters([
'client' => $client,
'user' => $user,
'scopes' => $scopes,
'request' => $request,
'authToken' => $authToken,
]);
}
/**
* Transform the authorization requests's scopes into Scope instances.
*
* @param \League\OAuth2\Server\RequestTypes\AuthorizationRequest $authRequest
* @return array
*/
protected function parseScopes($authRequest)
{
return Passport::scopesFor(
collect($authRequest->getScopes())->map(function ($scope) {
return $scope->getIdentifier();
})->unique()->all()
);
}
/**
* Determine if a valid token exists for the given user, client, and scopes.
*
* @param \Laravel\Passport\TokenRepository $tokens
* @param \Illuminate\Contracts\Auth\Authenticatable $user
* @param \Laravel\Passport\Client $client
* @param array $scopes
* @return bool
*/
protected function hasValidToken($tokens, $user, $client, $scopes)
{
$token = $tokens->findValidToken($user, $client);
return $token && $token->scopes === collect($scopes)->pluck('id')->all();
}
/**
* Approve the authorization request.
*
* @param \League\OAuth2\Server\RequestTypes\AuthorizationRequest $authRequest
* @param \Illuminate\Contracts\Auth\Authenticatable $user
* @return \Illuminate\Http\Response
*/
protected function approveRequest($authRequest, $user)
{
$authRequest->setUser(new User($user->getAuthIdentifier()));
$authRequest->setAuthorizationApproved(true);
return $this->withErrorHandling(function () use ($authRequest) {
return $this->convertResponse(
$this->server->completeAuthorizationRequest($authRequest, new Psr7Response)
);
});
}
/**
* Deny the authorization request.
*
* @param \League\OAuth2\Server\RequestTypes\AuthorizationRequest $authRequest
* @param \Illuminate\Contracts\Auth\Authenticatable|null $user
* @return \Illuminate\Http\Response
*/
protected function denyRequest($authRequest, $user = null)
{
if (is_null($user)) {
$uri = $authRequest->getRedirectUri()
?? (is_array($authRequest->getClient()->getRedirectUri())
? $authRequest->getClient()->getRedirectUri()[0]
: $authRequest->getClient()->getRedirectUri());
$separator = $authRequest->getGrantTypeId() === 'implicit' ? '#' : '?';
$uri = $uri.(str_contains($uri, $separator) ? '&' : $separator).'state='.$authRequest->getState();
return $this->withErrorHandling(function () use ($uri) {
throw OAuthServerException::accessDenied('Unauthenticated', $uri);
});
}
$authRequest->setUser(new User($user->getAuthIdentifier()));
$authRequest->setAuthorizationApproved(false);
return $this->withErrorHandling(function () use ($authRequest) {
return $this->convertResponse(
$this->server->completeAuthorizationRequest($authRequest, new Psr7Response)
);
});
}
/**
* Prompt the user to login by throwing an AuthenticationException.
*
* @param \Illuminate\Http\Request $request
*
* @throws \Laravel\Passport\Exceptions\AuthenticationException
*/
protected function promptForLogin($request)
{
$request->session()->put('promptedForLogin', true);
throw new AuthenticationException;
}
}
@@ -0,0 +1,77 @@
<?php
namespace Laravel\Passport\Http\Controllers;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Laravel\Passport\RefreshTokenRepository;
use Laravel\Passport\TokenRepository;
class AuthorizedAccessTokenController
{
/**
* The token repository implementation.
*
* @var \Laravel\Passport\TokenRepository
*/
protected $tokenRepository;
/**
* The refresh token repository implementation.
*
* @var \Laravel\Passport\RefreshTokenRepository
*/
protected $refreshTokenRepository;
/**
* Create a new controller instance.
*
* @param \Laravel\Passport\TokenRepository $tokenRepository
* @param \Laravel\Passport\RefreshTokenRepository $refreshTokenRepository
* @return void
*/
public function __construct(TokenRepository $tokenRepository, RefreshTokenRepository $refreshTokenRepository)
{
$this->tokenRepository = $tokenRepository;
$this->refreshTokenRepository = $refreshTokenRepository;
}
/**
* Get all of the authorized tokens for the authenticated user.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Database\Eloquent\Collection
*/
public function forUser(Request $request)
{
$tokens = $this->tokenRepository->forUser($request->user()->getAuthIdentifier());
return $tokens->load('client')->filter(function ($token) {
return ! $token->client->firstParty() && ! $token->revoked;
})->values();
}
/**
* Delete the given token.
*
* @param \Illuminate\Http\Request $request
* @param string $tokenId
* @return \Illuminate\Http\Response
*/
public function destroy(Request $request, $tokenId)
{
$token = $this->tokenRepository->findForUser(
$tokenId, $request->user()->getAuthIdentifier()
);
if (is_null($token)) {
return new Response('', 404);
}
$token->revoke();
$this->refreshTokenRepository->revokeRefreshTokensByAccessTokenId($tokenId);
return new Response('', Response::HTTP_NO_CONTENT);
}
}
@@ -0,0 +1,142 @@
<?php
namespace Laravel\Passport\Http\Controllers;
use Illuminate\Contracts\Validation\Factory as ValidationFactory;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Laravel\Passport\ClientRepository;
use Laravel\Passport\Http\Rules\RedirectRule;
use Laravel\Passport\Passport;
class ClientController
{
/**
* The client repository instance.
*
* @var \Laravel\Passport\ClientRepository
*/
protected $clients;
/**
* The validation factory implementation.
*
* @var \Illuminate\Contracts\Validation\Factory
*/
protected $validation;
/**
* The redirect validation rule.
*
* @var \Laravel\Passport\Http\Rules\RedirectRule
*/
protected $redirectRule;
/**
* Create a client controller instance.
*
* @param \Laravel\Passport\ClientRepository $clients
* @param \Illuminate\Contracts\Validation\Factory $validation
* @param \Laravel\Passport\Http\Rules\RedirectRule $redirectRule
* @return void
*/
public function __construct(
ClientRepository $clients,
ValidationFactory $validation,
RedirectRule $redirectRule
) {
$this->clients = $clients;
$this->validation = $validation;
$this->redirectRule = $redirectRule;
}
/**
* Get all of the clients for the authenticated user.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Database\Eloquent\Collection
*/
public function forUser(Request $request)
{
$userId = $request->user()->getAuthIdentifier();
$clients = $this->clients->activeForUser($userId);
if (Passport::$hashesClientSecrets) {
return $clients;
}
return $clients->makeVisible('secret');
}
/**
* Store a new client.
*
* @param \Illuminate\Http\Request $request
* @return \Laravel\Passport\Client|array
*/
public function store(Request $request)
{
$this->validation->make($request->all(), [
'name' => 'required|max:191',
'redirect' => ['required', $this->redirectRule],
'confidential' => 'boolean',
])->validate();
$client = $this->clients->create(
$request->user()->getAuthIdentifier(), $request->name, $request->redirect,
null, false, false, (bool) $request->input('confidential', true)
);
if (Passport::$hashesClientSecrets) {
return ['plainSecret' => $client->plainSecret] + $client->toArray();
}
return $client->makeVisible('secret');
}
/**
* Update the given client.
*
* @param \Illuminate\Http\Request $request
* @param string $clientId
* @return \Illuminate\Http\Response|\Laravel\Passport\Client
*/
public function update(Request $request, $clientId)
{
$client = $this->clients->findForUser($clientId, $request->user()->getAuthIdentifier());
if (! $client) {
return new Response('', 404);
}
$this->validation->make($request->all(), [
'name' => 'required|max:191',
'redirect' => ['required', $this->redirectRule],
])->validate();
return $this->clients->update(
$client, $request->name, $request->redirect
);
}
/**
* Delete the given client.
*
* @param \Illuminate\Http\Request $request
* @param string $clientId
* @return \Illuminate\Http\Response
*/
public function destroy(Request $request, $clientId)
{
$client = $this->clients->findForUser($clientId, $request->user()->getAuthIdentifier());
if (! $client) {
return new Response('', 404);
}
$this->clients->delete($client);
return new Response('', Response::HTTP_NO_CONTENT);
}
}
@@ -0,0 +1,23 @@
<?php
namespace Laravel\Passport\Http\Controllers;
use Illuminate\Http\Response;
trait ConvertsPsrResponses
{
/**
* Convert a PSR7 response to a Illuminate Response.
*
* @param \Psr\Http\Message\ResponseInterface $psrResponse
* @return \Illuminate\Http\Response
*/
public function convertResponse($psrResponse)
{
return new Response(
$psrResponse->getBody(),
$psrResponse->getStatusCode(),
$psrResponse->getHeaders()
);
}
}
@@ -0,0 +1,51 @@
<?php
namespace Laravel\Passport\Http\Controllers;
use Illuminate\Http\Request;
use League\OAuth2\Server\AuthorizationServer;
use Nyholm\Psr7\Response as Psr7Response;
class DenyAuthorizationController
{
use ConvertsPsrResponses, HandlesOAuthErrors, RetrievesAuthRequestFromSession;
/**
* The authorization server.
*
* @var \League\OAuth2\Server\AuthorizationServer
*/
protected $server;
/**
* Create a new controller instance.
*
* @param \League\OAuth2\Server\AuthorizationServer $server
* @return void
*/
public function __construct(AuthorizationServer $server)
{
$this->server = $server;
}
/**
* Deny the authorization request.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\RedirectResponse
*/
public function deny(Request $request)
{
$this->assertValidAuthToken($request);
$authRequest = $this->getAuthRequestFromSession($request);
$authRequest->setAuthorizationApproved(false);
return $this->withErrorHandling(function () use ($authRequest) {
return $this->convertResponse(
$this->server->completeAuthorizationRequest($authRequest, new Psr7Response)
);
});
}
}
@@ -0,0 +1,32 @@
<?php
namespace Laravel\Passport\Http\Controllers;
use Laravel\Passport\Exceptions\OAuthServerException;
use League\OAuth2\Server\Exception\OAuthServerException as LeagueException;
use Nyholm\Psr7\Response as Psr7Response;
trait HandlesOAuthErrors
{
use ConvertsPsrResponses;
/**
* Perform the given callback with exception handling.
*
* @param \Closure $callback
* @return mixed
*
* @throws \Laravel\Passport\Exceptions\OAuthServerException
*/
protected function withErrorHandling($callback)
{
try {
return $callback();
} catch (LeagueException $e) {
throw new OAuthServerException(
$e,
$this->convertResponse($e->generateHttpResponse(new Psr7Response))
);
}
}
}
@@ -0,0 +1,94 @@
<?php
namespace Laravel\Passport\Http\Controllers;
use Illuminate\Contracts\Validation\Factory as ValidationFactory;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Laravel\Passport\Passport;
use Laravel\Passport\TokenRepository;
class PersonalAccessTokenController
{
/**
* The token repository implementation.
*
* @var \Laravel\Passport\TokenRepository
*/
protected $tokenRepository;
/**
* The validation factory implementation.
*
* @var \Illuminate\Contracts\Validation\Factory
*/
protected $validation;
/**
* Create a controller instance.
*
* @param \Laravel\Passport\TokenRepository $tokenRepository
* @param \Illuminate\Contracts\Validation\Factory $validation
* @return void
*/
public function __construct(TokenRepository $tokenRepository, ValidationFactory $validation)
{
$this->validation = $validation;
$this->tokenRepository = $tokenRepository;
}
/**
* Get all of the personal access tokens for the authenticated user.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Database\Eloquent\Collection
*/
public function forUser(Request $request)
{
$tokens = $this->tokenRepository->forUser($request->user()->getAuthIdentifier());
return $tokens->load('client')->filter(function ($token) {
return $token->client->personal_access_client && ! $token->revoked;
})->values();
}
/**
* Create a new personal access token for the user.
*
* @param \Illuminate\Http\Request $request
* @return \Laravel\Passport\PersonalAccessTokenResult
*/
public function store(Request $request)
{
$this->validation->make($request->all(), [
'name' => 'required|max:191',
'scopes' => 'array|in:'.implode(',', Passport::scopeIds()),
])->validate();
return $request->user()->createToken(
$request->name, $request->scopes ?: []
);
}
/**
* Delete the given token.
*
* @param \Illuminate\Http\Request $request
* @param string $tokenId
* @return \Illuminate\Http\Response
*/
public function destroy(Request $request, $tokenId)
{
$token = $this->tokenRepository->findForUser(
$tokenId, $request->user()->getAuthIdentifier()
);
if (is_null($token)) {
return new Response('', 404);
}
$token->revoke();
return new Response('', Response::HTTP_NO_CONTENT);
}
}
@@ -0,0 +1,47 @@
<?php
namespace Laravel\Passport\Http\Controllers;
use Exception;
use Illuminate\Http\Request;
use Laravel\Passport\Bridge\User;
use Laravel\Passport\Exceptions\InvalidAuthTokenException;
trait RetrievesAuthRequestFromSession
{
/**
* Make sure the auth token matches the one in the session.
*
* @param \Illuminate\Http\Request $request
* @return void
*
* @throws \Laravel\Passport\Exceptions\InvalidAuthTokenException
*/
protected function assertValidAuthToken(Request $request)
{
if ($request->has('auth_token') && $request->session()->get('authToken') !== $request->get('auth_token')) {
$request->session()->forget(['authToken', 'authRequest']);
throw InvalidAuthTokenException::different();
}
}
/**
* Get the authorization request from the session.
*
* @param \Illuminate\Http\Request $request
* @return \League\OAuth2\Server\RequestTypes\AuthorizationRequest
*
* @throws \Exception
*/
protected function getAuthRequestFromSession(Request $request)
{
return tap($request->session()->get('authRequest'), function ($authRequest) use ($request) {
if (! $authRequest) {
throw new Exception('Authorization request was not present in the session.');
}
$authRequest->setUser(new User($request->user()->getAuthIdentifier()));
});
}
}
@@ -0,0 +1,18 @@
<?php
namespace Laravel\Passport\Http\Controllers;
use Laravel\Passport\Passport;
class ScopeController
{
/**
* Get all of the available scopes for the application.
*
* @return \Illuminate\Support\Collection
*/
public function all()
{
return Passport::scopes();
}
}
@@ -0,0 +1,41 @@
<?php
namespace Laravel\Passport\Http\Controllers;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Laravel\Passport\ApiTokenCookieFactory;
class TransientTokenController
{
/**
* The cookie factory instance.
*
* @var \Laravel\Passport\ApiTokenCookieFactory
*/
protected $cookieFactory;
/**
* Create a new controller instance.
*
* @param \Laravel\Passport\ApiTokenCookieFactory $cookieFactory
* @return void
*/
public function __construct(ApiTokenCookieFactory $cookieFactory)
{
$this->cookieFactory = $cookieFactory;
}
/**
* Get a fresh transient token cookie for the authenticated user.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function refresh(Request $request)
{
return (new Response('Refreshed.'))->withCookie($this->cookieFactory->make(
$request->user()->getAuthIdentifier(), $request->session()->token()
));
}
}
@@ -0,0 +1,46 @@
<?php
namespace Laravel\Passport\Http\Middleware;
use Laravel\Passport\Exceptions\AuthenticationException;
use Laravel\Passport\Exceptions\MissingScopeException;
class CheckClientCredentials extends CheckCredentials
{
/**
* Validate token credentials.
*
* @param \Laravel\Passport\Token $token
* @return void
*
* @throws \Laravel\Passport\Exceptions\AuthenticationException
*/
protected function validateCredentials($token)
{
if (! $token) {
throw new AuthenticationException;
}
}
/**
* Validate token credentials.
*
* @param \Laravel\Passport\Token $token
* @param array $scopes
* @return void
*
* @throws \Laravel\Passport\Exceptions\MissingScopeException
*/
protected function validateScopes($token, $scopes)
{
if (in_array('*', $token->scopes)) {
return;
}
foreach ($scopes as $scope) {
if ($token->cant($scope)) {
throw new MissingScopeException($scope);
}
}
}
}
@@ -0,0 +1,48 @@
<?php
namespace Laravel\Passport\Http\Middleware;
use Laravel\Passport\Exceptions\AuthenticationException;
use Laravel\Passport\Exceptions\MissingScopeException;
class CheckClientCredentialsForAnyScope extends CheckCredentials
{
/**
* Validate token credentials.
*
* @param \Laravel\Passport\Token $token
* @return void
*
* @throws \Laravel\Passport\Exceptions\AuthenticationException
*/
protected function validateCredentials($token)
{
if (! $token) {
throw new AuthenticationException;
}
}
/**
* Validate token credentials.
*
* @param \Laravel\Passport\Token $token
* @param array $scopes
* @return void
*
* @throws \Laravel\Passport\Exceptions\MissingScopeException
*/
protected function validateScopes($token, $scopes)
{
if (in_array('*', $token->scopes)) {
return;
}
foreach ($scopes as $scope) {
if ($token->can($scope)) {
return;
}
}
throw new MissingScopeException($scopes);
}
}
@@ -0,0 +1,125 @@
<?php
namespace Laravel\Passport\Http\Middleware;
use Closure;
use Laravel\Passport\Exceptions\AuthenticationException;
use Laravel\Passport\TokenRepository;
use League\OAuth2\Server\Exception\OAuthServerException;
use League\OAuth2\Server\ResourceServer;
use Nyholm\Psr7\Factory\Psr17Factory;
use Symfony\Bridge\PsrHttpMessage\Factory\PsrHttpFactory;
abstract class CheckCredentials
{
/**
* The Resource Server instance.
*
* @var \League\OAuth2\Server\ResourceServer
*/
protected $server;
/**
* Token Repository.
*
* @var \Laravel\Passport\TokenRepository
*/
protected $repository;
/**
* Create a new middleware instance.
*
* @param \League\OAuth2\Server\ResourceServer $server
* @param \Laravel\Passport\TokenRepository $repository
* @return void
*/
public function __construct(ResourceServer $server, TokenRepository $repository)
{
$this->server = $server;
$this->repository = $repository;
}
/**
* Specify the scopes for the middleware.
*
* @param array|string $scopes
* @return string
*/
public static function using(...$scopes)
{
if (is_array($scopes[0])) {
return static::class.':'.implode(',', $scopes[0]);
}
return static::class.':'.implode(',', $scopes);
}
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @param mixed ...$scopes
* @return mixed
*
* @throws \Laravel\Passport\Exceptions\AuthenticationException
*/
public function handle($request, Closure $next, ...$scopes)
{
$psr = (new PsrHttpFactory(
new Psr17Factory,
new Psr17Factory,
new Psr17Factory,
new Psr17Factory
))->createRequest($request);
try {
$psr = $this->server->validateAuthenticatedRequest($psr);
} catch (OAuthServerException $e) {
throw new AuthenticationException;
}
$this->validate($psr, $scopes);
return $next($request);
}
/**
* Validate the scopes and token on the incoming request.
*
* @param \Psr\Http\Message\ServerRequestInterface $psr
* @param array $scopes
* @return void
*
* @throws \Laravel\Passport\Exceptions\MissingScopeException|\Illuminate\Auth\AuthenticationException
*/
protected function validate($psr, $scopes)
{
$token = $this->repository->find($psr->getAttribute('oauth_access_token_id'));
$this->validateCredentials($token);
$this->validateScopes($token, $scopes);
}
/**
* Validate token credentials.
*
* @param \Laravel\Passport\Token $token
* @return void
*
* @throws \Laravel\Passport\Exceptions\AuthenticationException
*/
abstract protected function validateCredentials($token);
/**
* Validate token scopes.
*
* @param \Laravel\Passport\Token $token
* @param array $scopes
* @return void
*
* @throws \Laravel\Passport\Exceptions\MissingScopeException
*/
abstract protected function validateScopes($token, $scopes);
}
@@ -0,0 +1,49 @@
<?php
namespace Laravel\Passport\Http\Middleware;
use Laravel\Passport\Exceptions\AuthenticationException;
use Laravel\Passport\Exceptions\MissingScopeException;
class CheckForAnyScope
{
/**
* Specify the scopes for the middleware.
*
* @param array|string $scopes
* @return string
*/
public static function using(...$scopes)
{
if (is_array($scopes[0])) {
return static::class.':'.implode(',', $scopes[0]);
}
return static::class.':'.implode(',', $scopes);
}
/**
* Handle the incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @param mixed ...$scopes
* @return \Illuminate\Http\Response
*
* @throws \Laravel\Passport\Exceptions\AuthenticationException|\Laravel\Passport\Exceptions\MissingScopeException
*/
public function handle($request, $next, ...$scopes)
{
if (! $request->user() || ! $request->user()->token()) {
throw new AuthenticationException;
}
foreach ($scopes as $scope) {
if ($request->user()->tokenCan($scope)) {
return $next($request);
}
}
throw new MissingScopeException($scopes);
}
}
@@ -0,0 +1,49 @@
<?php
namespace Laravel\Passport\Http\Middleware;
use Laravel\Passport\Exceptions\AuthenticationException;
use Laravel\Passport\Exceptions\MissingScopeException;
class CheckScopes
{
/**
* Specify the scopes for the middleware.
*
* @param array|string $scopes
* @return string
*/
public static function using(...$scopes)
{
if (is_array($scopes[0])) {
return static::class.':'.implode(',', $scopes[0]);
}
return static::class.':'.implode(',', $scopes);
}
/**
* Handle the incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @param mixed ...$scopes
* @return \Illuminate\Http\Response
*
* @throws \Laravel\Passport\Exceptions\AuthenticationException|\Laravel\Passport\Exceptions\MissingScopeException
*/
public function handle($request, $next, ...$scopes)
{
if (! $request->user() || ! $request->user()->token()) {
throw new AuthenticationException;
}
foreach ($scopes as $scope) {
if (! $request->user()->tokenCan($scope)) {
throw new MissingScopeException($scope);
}
}
return $next($request);
}
}
@@ -0,0 +1,129 @@
<?php
namespace Laravel\Passport\Http\Middleware;
use Closure;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Response;
use Laravel\Passport\ApiTokenCookieFactory;
use Laravel\Passport\Passport;
class CreateFreshApiToken
{
/**
* The API token cookie factory instance.
*
* @var \Laravel\Passport\ApiTokenCookieFactory
*/
protected $cookieFactory;
/**
* The authentication guard.
*
* @var string
*/
protected $guard;
/**
* Create a new middleware instance.
*
* @param \Laravel\Passport\ApiTokenCookieFactory $cookieFactory
* @return void
*/
public function __construct(ApiTokenCookieFactory $cookieFactory)
{
$this->cookieFactory = $cookieFactory;
}
/**
* Specify the guard for the middleware.
*
* @param string|null $guard
* @return string
*/
public static function using($guard = null)
{
$guard = is_null($guard) ? '' : ':'.$guard;
return static::class.$guard;
}
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @param string|null $guard
* @return mixed
*/
public function handle($request, Closure $next, $guard = null)
{
$this->guard = $guard;
$response = $next($request);
if ($this->shouldReceiveFreshToken($request, $response)) {
$response->withCookie($this->cookieFactory->make(
$request->user($this->guard)->getAuthIdentifier(), $request->session()->token()
));
}
return $response;
}
/**
* Determine if the given request should receive a fresh token.
*
* @param \Illuminate\Http\Request $request
* @param \Illuminate\Http\Response $response
* @return bool
*/
protected function shouldReceiveFreshToken($request, $response)
{
return $this->requestShouldReceiveFreshToken($request) &&
$this->responseShouldReceiveFreshToken($response);
}
/**
* Determine if the request should receive a fresh token.
*
* @param \Illuminate\Http\Request $request
* @return bool
*/
protected function requestShouldReceiveFreshToken($request)
{
return $request->isMethod('GET') && $request->user($this->guard);
}
/**
* Determine if the response should receive a fresh token.
*
* @param \Illuminate\Http\Response $response
* @return bool
*/
protected function responseShouldReceiveFreshToken($response)
{
return ($response instanceof Response ||
$response instanceof JsonResponse) &&
! $this->alreadyContainsToken($response);
}
/**
* Determine if the given response already contains an API token.
*
* This avoids us overwriting a just "refreshed" token.
*
* @param \Illuminate\Http\Response $response
* @return bool
*/
protected function alreadyContainsToken($response)
{
foreach ($response->headers->getCookies() as $cookie) {
if ($cookie->getName() === Passport::cookie()) {
return true;
}
}
return false;
}
}
@@ -0,0 +1,68 @@
<?php
namespace Laravel\Passport\Http\Responses;
use Illuminate\Contracts\Support\Responsable;
use Laravel\Passport\Contracts\AuthorizationViewResponse as AuthorizationViewResponseContract;
class AuthorizationViewResponse implements AuthorizationViewResponseContract
{
/**
* The name of the view or the callable used to generate the view.
*
* @var string
*/
protected $view;
/**
* An array of arguments that may be passed to the view response and used in the view.
*
* @var string
*/
protected $parameters;
/**
* Create a new response instance.
*
* @param callable|string $view
* @return void
*/
public function __construct($view)
{
$this->view = $view;
}
/**
* Add parameters to response.
*
* @param array $parameters
* @return $this
*/
public function withParameters($parameters = [])
{
$this->parameters = $parameters;
return $this;
}
/**
* Create an HTTP response that represents the object.
*
* @param \Illuminate\Http\Request $request
* @return \Symfony\Component\HttpFoundation\Response
*/
public function toResponse($request)
{
if (! is_callable($this->view) || is_string($this->view)) {
return response()->view($this->view, $this->parameters);
}
$response = call_user_func($this->view, $this->parameters);
if ($response instanceof Responsable) {
return $response->toResponse($request);
}
return $response;
}
}
@@ -0,0 +1,51 @@
<?php
namespace Laravel\Passport\Http\Rules;
use Illuminate\Contracts\Validation\Factory;
use Illuminate\Contracts\Validation\Rule;
class RedirectRule implements Rule
{
/**
* The validator instance.
*
* @var \Illuminate\Contracts\Validation\Factory
*/
protected $validator;
/**
* Create a new rule instance.
*
* @param \Illuminate\Contracts\Validation\Factory $validator
* @return void
*/
public function __construct(Factory $validator)
{
$this->validator = $validator;
}
/**
* {@inheritdoc}
*/
public function passes($attribute, $value)
{
foreach (explode(',', $value) as $redirect) {
$validator = $this->validator->make(['redirect' => $redirect], ['redirect' => new UriRule]);
if ($validator->fails()) {
return false;
}
}
return true;
}
/**
* {@inheritdoc}
*/
public function message()
{
return 'One or more redirects have an invalid URI format.';
}
}
@@ -0,0 +1,28 @@
<?php
namespace Laravel\Passport\Http\Rules;
use Illuminate\Contracts\Validation\Rule;
class UriRule implements Rule
{
/**
* {@inheritdoc}
*/
public function passes($attribute, $value): bool
{
if (filter_var($value, FILTER_VALIDATE_URL)) {
return true;
}
return false;
}
/**
* {@inheritdoc}
*/
public function message(): string
{
return 'The :attribute must be valid URI.';
}
}
+758
View File
@@ -0,0 +1,758 @@
<?php
namespace Laravel\Passport;
use Carbon\Carbon;
use DateInterval;
use DateTimeInterface;
use Illuminate\Contracts\Encryption\Encrypter;
use Laravel\Passport\Contracts\AuthorizationViewResponse as AuthorizationViewResponseContract;
use Laravel\Passport\Http\Responses\AuthorizationViewResponse;
use League\OAuth2\Server\ResourceServer;
use Mockery;
use Psr\Http\Message\ServerRequestInterface;
class Passport
{
/**
* Indicates if the implicit grant type is enabled.
*
* @var bool|null
*/
public static $implicitGrantEnabled = false;
/**
* Indicates if the password grant type is enabled.
*
* @var bool|null
*/
public static $passwordGrantEnabled = true;
/**
* The default scope.
*
* @var string
*/
public static $defaultScope;
/**
* All of the scopes defined for the application.
*
* @var array
*/
public static $scopes = [
//
];
/**
* The interval when access tokens expire.
*
* @var \DateInterval|null
*/
public static $tokensExpireIn;
/**
* The date when refresh tokens expire.
*
* @var \DateInterval|null
*/
public static $refreshTokensExpireIn;
/**
* The date when personal access tokens expire.
*
* @var \DateInterval|null
*/
public static $personalAccessTokensExpireIn;
/**
* The name for API token cookies.
*
* @var string
*/
public static $cookie = 'laravel_token';
/**
* Indicates if Passport should ignore incoming CSRF tokens.
*
* @var bool
*/
public static $ignoreCsrfToken = false;
/**
* The storage location of the encryption keys.
*
* @var string
*/
public static $keyPath;
/**
* The access token entity class name.
*
* @var string
*/
public static $accessTokenEntity = 'Laravel\Passport\Bridge\AccessToken';
/**
* The auth code model class name.
*
* @var string
*/
public static $authCodeModel = 'Laravel\Passport\AuthCode';
/**
* The client model class name.
*
* @var string
*/
public static $clientModel = 'Laravel\Passport\Client';
/**
* Indicates if client's are identified by UUIDs.
*
* @var bool
*/
public static $clientUuids = false;
/**
* The personal access client model class name.
*
* @var string
*/
public static $personalAccessClientModel = 'Laravel\Passport\PersonalAccessClient';
/**
* The token model class name.
*
* @var string
*/
public static $tokenModel = 'Laravel\Passport\Token';
/**
* The refresh token model class name.
*
* @var string
*/
public static $refreshTokenModel = 'Laravel\Passport\RefreshToken';
/**
* Indicates if Passport migrations will be run.
*
* @var bool
*/
public static $runsMigrations = true;
/**
* Indicates if Passport should unserializes cookies.
*
* @var bool
*/
public static $unserializesCookies = false;
/**
* Indicates if Passport should decrypt cookies.
*
* @var bool
*/
public static $decryptsCookies = true;
/**
* Indicates if client secrets will be hashed.
*
* @var bool
*/
public static $hashesClientSecrets = false;
/**
* The callback that should be used to generate JWT encryption keys.
*
* @var callable
*/
public static $tokenEncryptionKeyCallback;
/**
* Indicates the scope should inherit its parent scope.
*
* @var bool
*/
public static $withInheritedScopes = false;
/**
* The authorization server response type.
*
* @var \League\OAuth2\Server\ResponseTypes\ResponseTypeInterface|null
*/
public static $authorizationServerResponseType;
/**
* Indicates if Passport routes will be registered.
*
* @var bool
*/
public static $registersRoutes = true;
/**
* Enable the implicit grant type.
*
* @return static
*/
public static function enableImplicitGrant()
{
static::$implicitGrantEnabled = true;
return new static;
}
/**
* Set the default scope(s). Multiple scopes may be an array or specified delimited by spaces.
*
* @param array|string $scope
* @return void
*/
public static function setDefaultScope($scope)
{
static::$defaultScope = is_array($scope) ? implode(' ', $scope) : $scope;
}
/**
* Get all of the defined scope IDs.
*
* @return array
*/
public static function scopeIds()
{
return static::scopes()->pluck('id')->values()->all();
}
/**
* Determine if the given scope has been defined.
*
* @param string $id
* @return bool
*/
public static function hasScope($id)
{
return $id === '*' || array_key_exists($id, static::$scopes);
}
/**
* Get all of the scopes defined for the application.
*
* @return \Illuminate\Support\Collection
*/
public static function scopes()
{
return collect(static::$scopes)->map(function ($description, $id) {
return new Scope($id, $description);
})->values();
}
/**
* Get all of the scopes matching the given IDs.
*
* @param array $ids
* @return array
*/
public static function scopesFor(array $ids)
{
return collect($ids)->map(function ($id) {
if (isset(static::$scopes[$id])) {
return new Scope($id, static::$scopes[$id]);
}
})->filter()->values()->all();
}
/**
* Define the scopes for the application.
*
* @param array $scopes
* @return void
*/
public static function tokensCan(array $scopes)
{
static::$scopes = $scopes;
}
/**
* Get or set when access tokens expire.
*
* @param \DateTimeInterface|null $date
* @return \DateInterval|static
*/
public static function tokensExpireIn(DateTimeInterface $date = null)
{
if (is_null($date)) {
return static::$tokensExpireIn ?? new DateInterval('P1Y');
}
static::$tokensExpireIn = Carbon::now()->diff($date);
return new static;
}
/**
* Get or set when refresh tokens expire.
*
* @param \DateTimeInterface|null $date
* @return \DateInterval|static
*/
public static function refreshTokensExpireIn(DateTimeInterface $date = null)
{
if (is_null($date)) {
return static::$refreshTokensExpireIn ?? new DateInterval('P1Y');
}
static::$refreshTokensExpireIn = Carbon::now()->diff($date);
return new static;
}
/**
* Get or set when personal access tokens expire.
*
* @param \DateTimeInterface|null $date
* @return \DateInterval|static
*/
public static function personalAccessTokensExpireIn(DateTimeInterface $date = null)
{
if (is_null($date)) {
return static::$personalAccessTokensExpireIn ?? new DateInterval('P1Y');
}
static::$personalAccessTokensExpireIn = Carbon::now()->diff($date);
return new static;
}
/**
* Get or set the name for API token cookies.
*
* @param string|null $cookie
* @return string|static
*/
public static function cookie($cookie = null)
{
if (is_null($cookie)) {
return static::$cookie;
}
static::$cookie = $cookie;
return new static;
}
/**
* Indicate that Passport should ignore incoming CSRF tokens.
*
* @param bool $ignoreCsrfToken
* @return static
*/
public static function ignoreCsrfToken($ignoreCsrfToken = true)
{
static::$ignoreCsrfToken = $ignoreCsrfToken;
return new static;
}
/**
* Set the current user for the application with the given scopes.
*
* @param \Illuminate\Contracts\Auth\Authenticatable|\Laravel\Passport\HasApiTokens $user
* @param array $scopes
* @param string $guard
* @return \Illuminate\Contracts\Auth\Authenticatable
*/
public static function actingAs($user, $scopes = [], $guard = 'api')
{
$token = app(self::tokenModel());
$token->scopes = $scopes;
$user->withAccessToken($token);
if (isset($user->wasRecentlyCreated) && $user->wasRecentlyCreated) {
$user->wasRecentlyCreated = false;
}
app('auth')->guard($guard)->setUser($user);
app('auth')->shouldUse($guard);
return $user;
}
/**
* Set the current client for the application with the given scopes.
*
* @param \Laravel\Passport\Client $client
* @param array $scopes
* @param string $guard
* @return \Laravel\Passport\Client
*/
public static function actingAsClient($client, $scopes = [], $guard = 'api')
{
$token = app(self::tokenModel());
$token->client_id = $client->getKey();
$token->setRelation('client', $client);
$token->scopes = $scopes;
$mock = Mockery::mock(ResourceServer::class);
$mock->shouldReceive('validateAuthenticatedRequest')
->andReturnUsing(function (ServerRequestInterface $request) use ($token) {
return $request->withAttribute('oauth_client_id', $token->client->id)
->withAttribute('oauth_access_token_id', $token->id)
->withAttribute('oauth_scopes', $token->scopes);
});
app()->instance(ResourceServer::class, $mock);
$mock = Mockery::mock(TokenRepository::class);
$mock->shouldReceive('find')->andReturn($token);
app()->instance(TokenRepository::class, $mock);
app('auth')->guard($guard)->setClient($client);
app('auth')->shouldUse($guard);
return $client;
}
/**
* Set the storage location of the encryption keys.
*
* @param string $path
* @return void
*/
public static function loadKeysFrom($path)
{
static::$keyPath = $path;
}
/**
* The location of the encryption keys.
*
* @param string $file
* @return string
*/
public static function keyPath($file)
{
$file = ltrim($file, '/\\');
return static::$keyPath
? rtrim(static::$keyPath, '/\\').DIRECTORY_SEPARATOR.$file
: storage_path($file);
}
/**
* Set the access token entity class name.
*
* @param string $accessTokenEntity
* @return void
*/
public static function useAccessTokenEntity($accessTokenEntity)
{
static::$accessTokenEntity = $accessTokenEntity;
}
/**
* Set the auth code model class name.
*
* @param string $authCodeModel
* @return void
*/
public static function useAuthCodeModel($authCodeModel)
{
static::$authCodeModel = $authCodeModel;
}
/**
* Get the auth code model class name.
*
* @return string
*/
public static function authCodeModel()
{
return static::$authCodeModel;
}
/**
* Get a new auth code model instance.
*
* @return \Laravel\Passport\AuthCode
*/
public static function authCode()
{
return new static::$authCodeModel;
}
/**
* Set the client model class name.
*
* @param string $clientModel
* @return void
*/
public static function useClientModel($clientModel)
{
static::$clientModel = $clientModel;
}
/**
* Get the client model class name.
*
* @return string
*/
public static function clientModel()
{
return static::$clientModel;
}
/**
* Get a new client model instance.
*
* @return \Laravel\Passport\Client
*/
public static function client()
{
return new static::$clientModel;
}
/**
* Determine if clients are identified using UUIDs.
*
* @return bool
*/
public static function clientUuids()
{
return static::$clientUuids;
}
/**
* Specify if clients are identified using UUIDs.
*
* @param bool $value
* @return void
*/
public static function setClientUuids($value)
{
static::$clientUuids = $value;
}
/**
* Set the personal access client model class name.
*
* @param string $clientModel
* @return void
*/
public static function usePersonalAccessClientModel($clientModel)
{
static::$personalAccessClientModel = $clientModel;
}
/**
* Get the personal access client model class name.
*
* @return string
*/
public static function personalAccessClientModel()
{
return static::$personalAccessClientModel;
}
/**
* Get a new personal access client model instance.
*
* @return \Laravel\Passport\PersonalAccessClient
*/
public static function personalAccessClient()
{
return new static::$personalAccessClientModel;
}
/**
* Set the token model class name.
*
* @param string $tokenModel
* @return void
*/
public static function useTokenModel($tokenModel)
{
static::$tokenModel = $tokenModel;
}
/**
* Get the token model class name.
*
* @return string
*/
public static function tokenModel()
{
return static::$tokenModel;
}
/**
* Get a new personal access client model instance.
*
* @return \Laravel\Passport\Token
*/
public static function token()
{
return new static::$tokenModel;
}
/**
* Set the refresh token model class name.
*
* @param string $refreshTokenModel
* @return void
*/
public static function useRefreshTokenModel($refreshTokenModel)
{
static::$refreshTokenModel = $refreshTokenModel;
}
/**
* Get the refresh token model class name.
*
* @return string
*/
public static function refreshTokenModel()
{
return static::$refreshTokenModel;
}
/**
* Get a new refresh token model instance.
*
* @return \Laravel\Passport\RefreshToken
*/
public static function refreshToken()
{
return new static::$refreshTokenModel;
}
/**
* Configure Passport to hash client credential secrets.
*
* @return static
*/
public static function hashClientSecrets()
{
static::$hashesClientSecrets = true;
return new static;
}
/**
* Specify the callback that should be invoked to generate encryption keys for encrypting JWT tokens.
*
* @param callable $callback
* @return static
*/
public static function encryptTokensUsing($callback)
{
static::$tokenEncryptionKeyCallback = $callback;
return new static;
}
/**
* Generate an encryption key for encrypting JWT tokens.
*
* @param \Illuminate\Contracts\Encryption\Encrypter $encrypter
* @return string
*/
public static function tokenEncryptionKey(Encrypter $encrypter)
{
return is_callable(static::$tokenEncryptionKeyCallback) ?
(static::$tokenEncryptionKeyCallback)($encrypter) :
$encrypter->getKey();
}
/**
* Specify which view should be used as the authorization view.
*
* @param callable|string $view
* @return void
*/
public static function authorizationView($view)
{
app()->singleton(AuthorizationViewResponseContract::class, function ($app) use ($view) {
return new AuthorizationViewResponse($view);
});
}
/**
* Configure Passport to not register its routes.
*
* @return static
*/
public static function ignoreRoutes()
{
static::$registersRoutes = false;
return new static;
}
/**
* Configure Passport to not register its migrations.
*
* @return static
*/
public static function ignoreMigrations()
{
static::$runsMigrations = false;
return new static;
}
/**
* Instruct Passport to enable cookie serialization.
*
* @return static
*/
public static function withCookieSerialization()
{
static::$unserializesCookies = true;
return new static;
}
/**
* Instruct Passport to disable cookie serialization.
*
* @return static
*/
public static function withoutCookieSerialization()
{
static::$unserializesCookies = false;
return new static;
}
/**
* Instruct Passport to enable cookie encryption.
*
* @return static
*/
public static function withCookieEncryption()
{
static::$decryptsCookies = true;
return new static;
}
/**
* Instruct Passport to disable cookie encryption.
*
* @return static
*/
public static function withoutCookieEncryption()
{
static::$decryptsCookies = false;
return new static;
}
}
@@ -0,0 +1,384 @@
<?php
namespace Laravel\Passport;
use DateInterval;
use Illuminate\Auth\Events\Logout;
use Illuminate\Config\Repository as Config;
use Illuminate\Contracts\Auth\StatefulGuard;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Cookie;
use Illuminate\Support\Facades\Event;
use Illuminate\Support\Facades\Request;
use Illuminate\Support\Facades\Route;
use Illuminate\Support\ServiceProvider;
use Laravel\Passport\Bridge\PersonalAccessGrant;
use Laravel\Passport\Bridge\RefreshTokenRepository;
use Laravel\Passport\Guards\TokenGuard;
use Laravel\Passport\Http\Controllers\AuthorizationController;
use Lcobucci\JWT\Encoding\JoseEncoder;
use Lcobucci\JWT\Parser as ParserContract;
use Lcobucci\JWT\Token\Parser;
use League\OAuth2\Server\AuthorizationServer;
use League\OAuth2\Server\CryptKey;
use League\OAuth2\Server\Grant\AuthCodeGrant;
use League\OAuth2\Server\Grant\ClientCredentialsGrant;
use League\OAuth2\Server\Grant\ImplicitGrant;
use League\OAuth2\Server\Grant\PasswordGrant;
use League\OAuth2\Server\Grant\RefreshTokenGrant;
use League\OAuth2\Server\ResourceServer;
class PassportServiceProvider extends ServiceProvider
{
/**
* Bootstrap the application services.
*
* @return void
*/
public function boot()
{
$this->registerRoutes();
$this->registerResources();
$this->registerMigrations();
$this->registerPublishing();
$this->registerCommands();
$this->deleteCookieOnLogout();
}
/**
* Register the Passport routes.
*
* @return void
*/
protected function registerRoutes()
{
if (Passport::$registersRoutes) {
Route::group([
'as' => 'passport.',
'prefix' => config('passport.path', 'oauth'),
'namespace' => 'Laravel\Passport\Http\Controllers',
], function () {
$this->loadRoutesFrom(__DIR__.'/../routes/web.php');
});
}
}
/**
* Register the Passport resources.
*
* @return void
*/
protected function registerResources()
{
$this->loadViewsFrom(__DIR__.'/../resources/views', 'passport');
}
/**
* Register the Passport migration files.
*
* @return void
*/
protected function registerMigrations()
{
if ($this->app->runningInConsole() && Passport::$runsMigrations && ! Passport::clientUuids()) {
$this->loadMigrationsFrom(__DIR__.'/../database/migrations');
}
}
/**
* Register the package's publishable resources.
*
* @return void
*/
protected function registerPublishing()
{
if ($this->app->runningInConsole()) {
$this->publishes([
__DIR__.'/../database/migrations' => database_path('migrations'),
], 'passport-migrations');
$this->publishes([
__DIR__.'/../resources/views' => base_path('resources/views/vendor/passport'),
], 'passport-views');
$this->publishes([
__DIR__.'/../config/passport.php' => config_path('passport.php'),
], 'passport-config');
}
}
/**
* Register the Passport Artisan commands.
*
* @return void
*/
protected function registerCommands()
{
if ($this->app->runningInConsole()) {
$this->commands([
Console\InstallCommand::class,
Console\ClientCommand::class,
Console\HashCommand::class,
Console\KeysCommand::class,
Console\PurgeCommand::class,
]);
}
}
/**
* Register the service provider.
*
* @return void
*/
public function register()
{
$this->mergeConfigFrom(__DIR__.'/../config/passport.php', 'passport');
Passport::setClientUuids($this->app->make(Config::class)->get('passport.client_uuids', false));
$this->app->when(AuthorizationController::class)
->needs(StatefulGuard::class)
->give(fn () => Auth::guard(config('passport.guard', null)));
$this->registerAuthorizationServer();
$this->registerClientRepository();
$this->registerJWTParser();
$this->registerResourceServer();
$this->registerGuard();
Passport::authorizationView('passport::authorize');
}
/**
* Register the authorization server.
*
* @return void
*/
protected function registerAuthorizationServer()
{
$this->app->singleton(AuthorizationServer::class, function () {
return tap($this->makeAuthorizationServer(), function ($server) {
$server->setDefaultScope(Passport::$defaultScope);
$server->enableGrantType(
$this->makeAuthCodeGrant(), Passport::tokensExpireIn()
);
$server->enableGrantType(
$this->makeRefreshTokenGrant(), Passport::tokensExpireIn()
);
if (Passport::$passwordGrantEnabled) {
$server->enableGrantType(
$this->makePasswordGrant(), Passport::tokensExpireIn()
);
}
$server->enableGrantType(
new PersonalAccessGrant, Passport::personalAccessTokensExpireIn()
);
$server->enableGrantType(
new ClientCredentialsGrant, Passport::tokensExpireIn()
);
if (Passport::$implicitGrantEnabled) {
$server->enableGrantType(
$this->makeImplicitGrant(), Passport::tokensExpireIn()
);
}
});
});
}
/**
* Create and configure an instance of the Auth Code grant.
*
* @return \League\OAuth2\Server\Grant\AuthCodeGrant
*/
protected function makeAuthCodeGrant()
{
return tap($this->buildAuthCodeGrant(), function ($grant) {
$grant->setRefreshTokenTTL(Passport::refreshTokensExpireIn());
});
}
/**
* Build the Auth Code grant instance.
*
* @return \League\OAuth2\Server\Grant\AuthCodeGrant
*/
protected function buildAuthCodeGrant()
{
return new AuthCodeGrant(
$this->app->make(Bridge\AuthCodeRepository::class),
$this->app->make(Bridge\RefreshTokenRepository::class),
new DateInterval('PT10M')
);
}
/**
* Create and configure a Refresh Token grant instance.
*
* @return \League\OAuth2\Server\Grant\RefreshTokenGrant
*/
protected function makeRefreshTokenGrant()
{
$repository = $this->app->make(RefreshTokenRepository::class);
return tap(new RefreshTokenGrant($repository), function ($grant) {
$grant->setRefreshTokenTTL(Passport::refreshTokensExpireIn());
});
}
/**
* Create and configure a Password grant instance.
*
* @return \League\OAuth2\Server\Grant\PasswordGrant
*/
protected function makePasswordGrant()
{
$grant = new PasswordGrant(
$this->app->make(Bridge\UserRepository::class),
$this->app->make(Bridge\RefreshTokenRepository::class)
);
$grant->setRefreshTokenTTL(Passport::refreshTokensExpireIn());
return $grant;
}
/**
* Create and configure an instance of the Implicit grant.
*
* @return \League\OAuth2\Server\Grant\ImplicitGrant
*/
protected function makeImplicitGrant()
{
return new ImplicitGrant(Passport::tokensExpireIn());
}
/**
* Make the authorization service instance.
*
* @return \League\OAuth2\Server\AuthorizationServer
*/
public function makeAuthorizationServer()
{
return new AuthorizationServer(
$this->app->make(Bridge\ClientRepository::class),
$this->app->make(Bridge\AccessTokenRepository::class),
$this->app->make(Bridge\ScopeRepository::class),
$this->makeCryptKey('private'),
app('encrypter')->getKey(),
Passport::$authorizationServerResponseType
);
}
/**
* Register the client repository.
*
* @return void
*/
protected function registerClientRepository()
{
$this->app->singleton(ClientRepository::class, function ($container) {
$config = $container->make('config')->get('passport.personal_access_client');
return new ClientRepository($config['id'] ?? null, $config['secret'] ?? null);
});
}
/**
* Register the JWT Parser.
*
* @return void
*/
protected function registerJWTParser()
{
$this->app->singleton(ParserContract::class, function () {
return new Parser(new JoseEncoder);
});
}
/**
* Register the resource server.
*
* @return void
*/
protected function registerResourceServer()
{
$this->app->singleton(ResourceServer::class, function ($container) {
return new ResourceServer(
$container->make(Bridge\AccessTokenRepository::class),
$this->makeCryptKey('public')
);
});
}
/**
* Create a CryptKey instance without permissions check.
*
* @param string $type
* @return \League\OAuth2\Server\CryptKey
*/
protected function makeCryptKey($type)
{
$key = str_replace('\\n', "\n", $this->app->make(Config::class)->get('passport.'.$type.'_key') ?? '');
if (! $key) {
$key = 'file://'.Passport::keyPath('oauth-'.$type.'.key');
}
return new CryptKey($key, null, false);
}
/**
* Register the token guard.
*
* @return void
*/
protected function registerGuard()
{
Auth::resolved(function ($auth) {
$auth->extend('passport', function ($app, $name, array $config) {
return tap($this->makeGuard($config), function ($guard) {
app()->refresh('request', $guard, 'setRequest');
});
});
});
}
/**
* Make an instance of the token guard.
*
* @param array $config
* @return \Laravel\Passport\Guards\TokenGuard
*/
protected function makeGuard(array $config)
{
return new TokenGuard(
$this->app->make(ResourceServer::class),
new PassportUserProvider(Auth::createUserProvider($config['provider']), $config['provider']),
$this->app->make(TokenRepository::class),
$this->app->make(ClientRepository::class),
$this->app->make('encrypter'),
$this->app->make('request')
);
}
/**
* Register the cookie deletion event handler.
*
* @return void
*/
protected function deleteCookieOnLogout()
{
Event::listen(Logout::class, function () {
if (Request::hasCookie(Passport::cookie())) {
Cookie::queue(Cookie::forget(Passport::cookie()));
}
});
}
}
@@ -0,0 +1,86 @@
<?php
namespace Laravel\Passport;
use Illuminate\Contracts\Auth\Authenticatable;
use Illuminate\Contracts\Auth\UserProvider;
class PassportUserProvider implements UserProvider
{
/**
* The user provider instance.
*
* @var \Illuminate\Contracts\Auth\UserProvider
*/
protected $provider;
/**
* The user provider name.
*
* @var string
*/
protected $providerName;
/**
* Create a new passport user provider.
*
* @param \Illuminate\Contracts\Auth\UserProvider $provider
* @param string $providerName
* @return void
*/
public function __construct(UserProvider $provider, $providerName)
{
$this->provider = $provider;
$this->providerName = $providerName;
}
/**
* {@inheritdoc}
*/
public function retrieveById($identifier)
{
return $this->provider->retrieveById($identifier);
}
/**
* {@inheritdoc}
*/
public function retrieveByToken($identifier, $token)
{
return $this->provider->retrieveByToken($identifier, $token);
}
/**
* {@inheritdoc}
*/
public function updateRememberToken(Authenticatable $user, $token)
{
$this->provider->updateRememberToken($user, $token);
}
/**
* {@inheritdoc}
*/
public function retrieveByCredentials(array $credentials)
{
return $this->provider->retrieveByCredentials($credentials);
}
/**
* {@inheritdoc}
*/
public function validateCredentials(Authenticatable $user, array $credentials)
{
return $this->provider->validateCredentials($user, $credentials);
}
/**
* Get the name of the user provider.
*
* @return string
*/
public function getProviderName()
{
return $this->providerName;
}
}
@@ -0,0 +1,32 @@
<?php
namespace Laravel\Passport;
use Illuminate\Database\Eloquent\Model;
class PersonalAccessClient extends Model
{
/**
* The database table used by the model.
*
* @var string
*/
protected $table = 'oauth_personal_access_clients';
/**
* The guarded attributes on the model.
*
* @var array
*/
protected $guarded = [];
/**
* Get all of the authentication codes for the client.
*
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function client()
{
return $this->belongsTo(Passport::clientModel());
}
}
@@ -0,0 +1,133 @@
<?php
namespace Laravel\Passport;
use Lcobucci\JWT\Parser as JwtParser;
use League\OAuth2\Server\AuthorizationServer;
use Nyholm\Psr7\Response;
use Nyholm\Psr7\ServerRequest;
use Psr\Http\Message\ServerRequestInterface;
class PersonalAccessTokenFactory
{
/**
* The authorization server instance.
*
* @var \League\OAuth2\Server\AuthorizationServer
*/
protected $server;
/**
* The client repository instance.
*
* @var \Laravel\Passport\ClientRepository
*/
protected $clients;
/**
* The token repository instance.
*
* @var \Laravel\Passport\TokenRepository
*/
protected $tokens;
/**
* The JWT token parser instance.
*
* @var \Lcobucci\JWT\Parser
*/
protected $jwt;
/**
* Create a new personal access token factory instance.
*
* @param \League\OAuth2\Server\AuthorizationServer $server
* @param \Laravel\Passport\ClientRepository $clients
* @param \Laravel\Passport\TokenRepository $tokens
* @param \Lcobucci\JWT\Parser $jwt
* @return void
*/
public function __construct(AuthorizationServer $server,
ClientRepository $clients,
TokenRepository $tokens,
JwtParser $jwt)
{
$this->jwt = $jwt;
$this->tokens = $tokens;
$this->server = $server;
$this->clients = $clients;
}
/**
* Create a new personal access token.
*
* @param mixed $userId
* @param string $name
* @param array $scopes
* @return \Laravel\Passport\PersonalAccessTokenResult
*/
public function make($userId, $name, array $scopes = [])
{
$response = $this->dispatchRequestToAuthorizationServer(
$this->createRequest($this->clients->personalAccessClient(), $userId, $scopes)
);
$token = tap($this->findAccessToken($response), function ($token) use ($userId, $name) {
$this->tokens->save($token->forceFill([
'user_id' => $userId,
'name' => $name,
]));
});
return new PersonalAccessTokenResult(
$response['access_token'], $token
);
}
/**
* Create a request instance for the given client.
*
* @param \Laravel\Passport\Client $client
* @param mixed $userId
* @param array $scopes
* @return \Psr\Http\Message\ServerRequestInterface
*/
protected function createRequest($client, $userId, array $scopes)
{
$secret = Passport::$hashesClientSecrets ? $this->clients->getPersonalAccessClientSecret() : $client->secret;
return (new ServerRequest('POST', 'not-important'))->withParsedBody([
'grant_type' => 'personal_access',
'client_id' => $client->getKey(),
'client_secret' => $secret,
'user_id' => $userId,
'scope' => implode(' ', $scopes),
]);
}
/**
* Dispatch the given request to the authorization server.
*
* @param \Psr\Http\Message\ServerRequestInterface $request
* @return array
*/
protected function dispatchRequestToAuthorizationServer(ServerRequestInterface $request)
{
return json_decode($this->server->respondToAccessTokenRequest(
$request, new Response
)->getBody()->__toString(), true);
}
/**
* Get the access token instance for the parsed response.
*
* @param array $response
* @return \Laravel\Passport\Token
*/
public function findAccessToken(array $response)
{
return $this->tokens->find(
$this->jwt->parse($response['access_token'])->claims()->get('jti')
);
}
}
@@ -0,0 +1,60 @@
<?php
namespace Laravel\Passport;
use Illuminate\Contracts\Support\Arrayable;
use Illuminate\Contracts\Support\Jsonable;
class PersonalAccessTokenResult implements Arrayable, Jsonable
{
/**
* The access token.
*
* @var string
*/
public $accessToken;
/**
* The token model instance.
*
* @var \Laravel\Passport\Token
*/
public $token;
/**
* Create a new result instance.
*
* @param string $accessToken
* @param \Laravel\Passport\Token $token
* @return void
*/
public function __construct($accessToken, $token)
{
$this->token = $token;
$this->accessToken = $accessToken;
}
/**
* Get the instance as an array.
*
* @return array
*/
public function toArray()
{
return [
'accessToken' => $this->accessToken,
'token' => $this->token,
];
}
/**
* Convert the object to its JSON representation.
*
* @param int $options
* @return string
*/
public function toJson($options = 0)
{
return json_encode($this->toArray(), $options);
}
}
+83
View File
@@ -0,0 +1,83 @@
<?php
namespace Laravel\Passport;
use Illuminate\Database\Eloquent\Model;
class RefreshToken extends Model
{
/**
* The database table used by the model.
*
* @var string
*/
protected $table = 'oauth_refresh_tokens';
/**
* The "type" of the primary key ID.
*
* @var string
*/
protected $keyType = 'string';
/**
* Indicates if the IDs are auto-incrementing.
*
* @var bool
*/
public $incrementing = false;
/**
* The guarded attributes on the model.
*
* @var array
*/
protected $guarded = [];
/**
* The attributes that should be cast to native types.
*
* @var array
*/
protected $casts = [
'revoked' => 'bool',
'expires_at' => 'datetime',
];
/**
* Indicates if the model should be timestamped.
*
* @var bool
*/
public $timestamps = false;
/**
* Get the access token that the refresh token belongs to.
*
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function accessToken()
{
return $this->belongsTo(Passport::tokenModel());
}
/**
* Revoke the token instance.
*
* @return bool
*/
public function revoke()
{
return $this->forceFill(['revoked' => true])->save();
}
/**
* Determine if the token is a transient JWT token.
*
* @return bool
*/
public function transient()
{
return false;
}
}
@@ -0,0 +1,76 @@
<?php
namespace Laravel\Passport;
class RefreshTokenRepository
{
/**
* Creates a new refresh token.
*
* @param array $attributes
* @return \Laravel\Passport\RefreshToken
*/
public function create($attributes)
{
return Passport::refreshToken()->create($attributes);
}
/**
* Gets a refresh token by the given ID.
*
* @param string $id
* @return \Laravel\Passport\RefreshToken
*/
public function find($id)
{
return Passport::refreshToken()->where('id', $id)->first();
}
/**
* Stores the given token instance.
*
* @param \Laravel\Passport\RefreshToken $token
* @return void
*/
public function save(RefreshToken $token)
{
$token->save();
}
/**
* Revokes the refresh token.
*
* @param string $id
* @return mixed
*/
public function revokeRefreshToken($id)
{
return Passport::refreshToken()->where('id', $id)->update(['revoked' => true]);
}
/**
* Revokes refresh tokens by access token id.
*
* @param string $tokenId
* @return mixed
*/
public function revokeRefreshTokensByAccessTokenId($tokenId)
{
return Passport::refreshToken()->where('access_token_id', $tokenId)->update(['revoked' => true]);
}
/**
* Checks if the refresh token has been revoked.
*
* @param string $id
* @return bool
*/
public function isRefreshTokenRevoked($id)
{
if ($token = $this->find($id)) {
return $token->revoked;
}
return true;
}
}
@@ -0,0 +1,27 @@
<?php
namespace Laravel\Passport;
trait ResolvesInheritedScopes
{
/**
* Resolve all possible scopes.
*
* @param string $scope
* @return array
*/
protected function resolveInheritedScopes($scope)
{
$parts = explode(':', $scope);
$partsCount = count($parts);
$scopes = [];
for ($i = 1; $i <= $partsCount; $i++) {
$scopes[] = implode(':', array_slice($parts, 0, $i));
}
return $scopes;
}
}
+60
View File
@@ -0,0 +1,60 @@
<?php
namespace Laravel\Passport;
use Illuminate\Contracts\Support\Arrayable;
use Illuminate\Contracts\Support\Jsonable;
class Scope implements Arrayable, Jsonable
{
/**
* The name / ID of the scope.
*
* @var string
*/
public $id;
/**
* The scope description.
*
* @var string
*/
public $description;
/**
* Create a new scope instance.
*
* @param string $id
* @param string $description
* @return void
*/
public function __construct($id, $description)
{
$this->id = $id;
$this->description = $description;
}
/**
* Get the instance as an array.
*
* @return array
*/
public function toArray()
{
return [
'id' => $this->id,
'description' => $this->description,
];
}
/**
* Convert the object to its JSON representation.
*
* @param int $options
* @return string
*/
public function toJson($options = 0)
{
return json_encode($this->toArray(), $options);
}
}
+129
View File
@@ -0,0 +1,129 @@
<?php
namespace Laravel\Passport;
use Illuminate\Database\Eloquent\Model;
class Token extends Model
{
use ResolvesInheritedScopes;
/**
* The database table used by the model.
*
* @var string
*/
protected $table = 'oauth_access_tokens';
/**
* The "type" of the primary key ID.
*
* @var string
*/
protected $keyType = 'string';
/**
* Indicates if the IDs are auto-incrementing.
*
* @var bool
*/
public $incrementing = false;
/**
* The guarded attributes on the model.
*
* @var array
*/
protected $guarded = [];
/**
* The attributes that should be cast to native types.
*
* @var array
*/
protected $casts = [
'scopes' => 'array',
'revoked' => 'bool',
'expires_at' => 'datetime',
];
/**
* Get the client that the token belongs to.
*
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function client()
{
return $this->belongsTo(Passport::clientModel());
}
/**
* Get the user that the token belongs to.
*
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function user()
{
$provider = config('auth.guards.api.provider');
$model = config('auth.providers.'.$provider.'.model');
return $this->belongsTo($model, 'user_id', (new $model)->getKeyName());
}
/**
* Determine if the token has a given scope.
*
* @param string $scope
* @return bool
*/
public function can($scope)
{
if (in_array('*', $this->scopes)) {
return true;
}
$scopes = Passport::$withInheritedScopes
? $this->resolveInheritedScopes($scope)
: [$scope];
foreach ($scopes as $scope) {
if (array_key_exists($scope, array_flip($this->scopes))) {
return true;
}
}
return false;
}
/**
* Determine if the token is missing a given scope.
*
* @param string $scope
* @return bool
*/
public function cant($scope)
{
return ! $this->can($scope);
}
/**
* Revoke the token instance.
*
* @return bool
*/
public function revoke()
{
return $this->forceFill(['revoked' => true])->save();
}
/**
* Determine if the token is a transient JWT token.
*
* @return bool
*/
public function transient()
{
return false;
}
}
+123
View File
@@ -0,0 +1,123 @@
<?php
namespace Laravel\Passport;
use Carbon\Carbon;
class TokenRepository
{
/**
* Creates a new Access Token.
*
* @param array $attributes
* @return \Laravel\Passport\Token
*/
public function create($attributes)
{
return Passport::token()->create($attributes);
}
/**
* Get a token by the given ID.
*
* @param string $id
* @return \Laravel\Passport\Token
*/
public function find($id)
{
return Passport::token()->where('id', $id)->first();
}
/**
* Get a token by the given user ID and token ID.
*
* @param string $id
* @param int $userId
* @return \Laravel\Passport\Token|null
*/
public function findForUser($id, $userId)
{
return Passport::token()->where('id', $id)->where('user_id', $userId)->first();
}
/**
* Get the token instances for the given user ID.
*
* @param mixed $userId
* @return \Illuminate\Database\Eloquent\Collection
*/
public function forUser($userId)
{
return Passport::token()->where('user_id', $userId)->get();
}
/**
* Get a valid token instance for the given user and client.
*
* @param \Illuminate\Contracts\Auth\Authenticatable $user
* @param \Laravel\Passport\Client $client
* @return \Laravel\Passport\Token|null
*/
public function getValidToken($user, $client)
{
return $client->tokens()
->whereUserId($user->getAuthIdentifier())
->where('revoked', 0)
->where('expires_at', '>', Carbon::now())
->first();
}
/**
* Store the given token instance.
*
* @param \Laravel\Passport\Token $token
* @return void
*/
public function save(Token $token)
{
$token->save();
}
/**
* Revoke an access token.
*
* @param string $id
* @return mixed
*/
public function revokeAccessToken($id)
{
return Passport::token()->where('id', $id)->update(['revoked' => true]);
}
/**
* Check if the access token has been revoked.
*
* @param string $id
* @return bool
*/
public function isAccessTokenRevoked($id)
{
if ($token = $this->find($id)) {
return $token->revoked;
}
return true;
}
/**
* Find a valid token for the given user and client.
*
* @param \Illuminate\Contracts\Auth\Authenticatable $user
* @param \Laravel\Passport\Client $client
* @return \Laravel\Passport\Token|null
*/
public function findValidToken($user, $client)
{
return $client->tokens()
->whereUserId($user->getAuthIdentifier())
->where('revoked', 0)
->where('expires_at', '>', Carbon::now())
->latest('expires_at')
->first();
}
}
+38
View File
@@ -0,0 +1,38 @@
<?php
namespace Laravel\Passport;
class TransientToken
{
/**
* Determine if the token has a given scope.
*
* @param string $scope
* @return bool
*/
public function can($scope)
{
return true;
}
/**
* Determine if the token is missing a given scope.
*
* @param string $scope
* @return bool
*/
public function cant($scope)
{
return false;
}
/**
* Determine if the token is a transient JWT token.
*
* @return bool
*/
public function transient()
{
return true;
}
}