Skip to content

Commit

Permalink
Update to use PHP 7.4+ language features and support Laravel 9 (#241)
Browse files Browse the repository at this point in the history
  • Loading branch information
evansims authored Jan 5, 2022
1 parent 3b67e9c commit 268b50e
Show file tree
Hide file tree
Showing 22 changed files with 1,082 additions and 60 deletions.
40 changes: 40 additions & 0 deletions config/auth0.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<?php

declare(strict_types=1);

return [
// Should be assigned either 'api', 'management', or 'webapp' to indicate your application's use case for the SDK. Determines what configuration options will be required at initialization.
'strategy' => env('AUTH0_STRATEGY', 'api'),

// Auth0 domain for your tenant, found in your Auth0 Application settings.
'domain' => env('AUTH0_DOMAIN'),

// If you have configured Auth0 to use a custom domain, configure it here.
'customDomain' => env('AUTH0_CUSTOM_DOMAIN'),

// Client ID, found in the Auth0 Application settings.
'clientId' => env('AUTH0_CLIENT_ID'),

// Authentication callback URI, as defined in your Auth0 Application settings.
'redirectUri' => env('AUTH0_REDIRECT_URI', env('APP_URL') . '/callback'),

// Client Secret, found in the Auth0 Application settings.
'clientSecret' => env('AUTH0_CLIENT_SECRET'),

// One or more API identifiers, found in your Auth0 API settings. The SDK uses the first value for building links. If provided, at least one of these values must match the 'aud' claim to validate an ID Token successfully.
'audience' => env('AUTH0_AUDIENCE', []),

// One or more Organization IDs, found in your Auth0 Organization settings. The SDK uses the first value for building links. If provided, at least one of these values must match the 'org_id' claim to validate an ID Token successfully.
'organization' => env('AUTH0_ORGANIZATION', []),

// The secret used to derive an encryption key for the user identity in a session cookie and to sign the transient cookies used by the login callback.
'cookieSecret' => env('AUTH0_COOKIE_SECRET', env('APP_KEY')),

// How long, in seconds, before cookies expire. If set to 0 the cookie will expire at the end of the session (when the browser closes).
'cookieExpires' => env('COOKIE_EXPIRES', 0),

// Named routes the SDK may call during stateful requests for redirections.
'routeLogin' => 'login',
'routeLogout' => 'logout',
'routeCallback' => 'callback',
];
225 changes: 225 additions & 0 deletions src/Auth/Guard.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,225 @@
<?php

declare(strict_types=1);

namespace Auth0\Laravel\Auth;

final class Guard implements \Illuminate\Contracts\Auth\Guard
{
/**
* The user provider implementation.
*
* @var \Illuminate\Contracts\Auth\UserProvider
*/
private $provider;

/**
* The request instance.
*
* @var \Illuminate\Http\Request
*/
private $request;

/**
* The name of the query string item from the request containing the API token.
*
* @var string
*/
private $inputKey;

/**
* The name of the token "column" in persistent storage.
*
* @var string
*/
private $storageKey;

/**
* Indicates if the API token is hashed in storage.
*
* @var bool
*/
private $hash = false;

/**
* Create a new authentication guard.
*
* @param \Illuminate\Contracts\Auth\UserProvider $provider
* @param \Illuminate\Http\Request $request
* @param string $inputKey
* @param string $storageKey
* @param bool $hash
*/
public function __construct(
\Illuminate\Contracts\Auth\UserProvider $provider,
\Illuminate\Http\Request $request,
$inputKey = 'api_token',
$storageKey = 'api_token',
$hash = false
) {
$this->provider = $provider;
$this->request = $request;
$this->inputKey = $inputKey;
$this->storageKey = $storageKey;
$this->hash = $hash;
}

/**
* Set the current user.
*
* @param \Illuminate\Contracts\Auth\Authenticatable $user
*/
public function login(
\Illuminate\Contracts\Auth\Authenticatable $user
): self {
$this->getInstance()->setUser($user);
return $this;
}

/**
* Clear the current user.
*/
public function logout(): self
{
$this->getInstance()->setUser(null);
app('auth0')->getSdk()->clear();
return $this;
}

/**
* Determine if the current user is authenticated.
*
* @return bool
*/
public function check(): bool
{
return $this->user() !== null;
}

/**
* Determine if the current user is a guest.
*
* @return bool
*/
public function guest(): bool
{
return ! $this->check();
}

/**
* Get the ID for the currently authenticated user.
*
* @return int|string|null
*/
public function id()
{
return $this->user() !== null ? $this->user()->getAuthIdentifier() : null;
}

/**
* Validate a user's credentials.
*
* @param array $credentials
*/
public function validate(
array $credentials = []
): bool {
if (! isset($credentials[$this->inputKey])) {
return false;
}

$credentials = [$this->storageKey => $credentials[$this->inputKey]];

return $this->provider->retrieveByCredentials($credentials) !== null;
}

/**
* Determine if the guard has a user instance.
*/
public function hasUser(): bool
{
return ! is_null($this->getInstance()->getUser());
}

/**
* Set the current user.
*
* @param \Illuminate\Contracts\Auth\Authenticatable $user
*/
public function setUser(
\Illuminate\Contracts\Auth\Authenticatable $user
): self {
$user = $this->getInstance()->setUser($user);
return $this;
}

/**
* Set the current request instance.
*
* @param \Illuminate\Http\Request $request
*/
public function setRequest(
\Illuminate\Http\Request $request
): self {
$this->request = $request;
return $this;
}

/**
* Get the currently authenticated user.
*/
public function user(): ?\Illuminate\Contracts\Auth\Authenticatable
{
$instance = $this->getInstance();
$user = $instance->getUser();

if ($user === null) {
$stateful = app('auth0')->getSdk()->getCredentials();

if ($stateful !== null) {
$user = $this->provider->retrieveByCredentials((array) $stateful);
}
}

if ($user === null) {
$token = $this->getTokenForRequest();

if ($token !== null) {
$user = $this->provider->retrieveByToken([], $token);
}
}

if ($user !== null) {
$instance->setUser($user);
}

return $user;
}

/**
* Get the token for the current request.
*/
public function getTokenForRequest(): ?string
{
$token = $this->request->query($this->inputKey);

if ($token === null) {
$token = $this->request->input($this->inputKey);
}

if ($token === null) {
$token = $this->request->bearerToken();
}

if ($token === null) {
$token = $this->request->getPassword();
}

return $token;
}

private function getInstance(): \Auth0\Laravel\StateInstance
{
return app()->make(\Auth0\Laravel\StateInstance::class);
}
}
107 changes: 107 additions & 0 deletions src/Auth/User/Provider.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
<?php

declare(strict_types=1);

namespace Auth0\Laravel\Auth\User;

final class Provider implements \Illuminate\Contracts\Auth\UserProvider
{
private Repository $repository;

private \Auth0\Laravel\Auth0 $service;

/**
* Auth0UserProvider constructor.
*
* @param \Auth0\Laravel\Auth\User\Repository $repository
*/
public function __construct(
Repository $repository
) {
$this->repository = $repository;
}

/**
* Returns a \Auth0\Laravel\Model\Stateless\User instance from an Id Token.
*/
public function retrieveById(
$identifier
): ?\Illuminate\Contracts\Auth\Authenticatable {
$decoded = app('auth0')->getSdk()->decode($identifier, null, null, null, null, null, null, \Auth0\SDK\Token::TYPE_ID_TOKEN)->toArray();
$scope = $decoded['scope'] ?? '';

// Process $identifier here ...
return $this->repository->fromAccessToken(
$decoded,
null,
$identifier,
explode(' ', $scope),
null,
null,
null,
);
}

/**
* Returns a \Auth0\Laravel\Model\Stateless\User instance from an Access Token.
*
* @phpcsSuppress SlevomatCodingStandard.Functions.UnusedParameter
*/
public function retrieveByToken(
$identifier,
$token
): ?\Illuminate\Contracts\Auth\Authenticatable {
$decoded = app('auth0')->getSdk()->decode($token, null, null, null, null, null, null, \Auth0\SDK\Token::TYPE_TOKEN)->toArray();
$scope = $decoded['scope'] ?? '';

return $this->repository->fromAccessToken(
$decoded,
null,
$token,
explode(' ', $scope),
null,
null,
null,
);
}

/**
* Returns a \Auth0\Laravel\Model\Stateless\User instance translated from an Auth0-PHP SDK session.
*/
public function retrieveByCredentials(
array $credentials
): ?\Illuminate\Contracts\Auth\Authenticatable {
return $this->repository->fromSession(
$credentials['user'] ?? null,
$credentials['idToken'] ?? null,
$credentials['accessToken'] ?? null,
$credentials['accessTokenScope'] ?? null,
$credentials['accessTokenExpiration'] ?? null,
$credentials['accessTokenExpired'] ?? null,
$credentials['refreshToken'] ?? null,
);
}

/**
* Returns true if the provided $user's unique identifier matches the credentials payload.
*
* @phpcsSuppress SlevomatCodingStandard.Functions.UnusedParameter
*/
public function validateCredentials(
\Illuminate\Contracts\Auth\Authenticatable $user,
array $credentials
): bool {
return false;
}

/**
* Method required by interface. Not supported.
*
* @phpcsSuppress SlevomatCodingStandard.Functions.UnusedParameter
*/
public function updateRememberToken(
\Illuminate\Contracts\Auth\Authenticatable $user,
$token
): void {
}
}
Loading

0 comments on commit 268b50e

Please sign in to comment.