$clientRedirectUris * @property-read Scope[]|Collection $scopes */ class Client extends Model implements ClientEntityInterface { use EntityTrait; protected $casts = [ 'id' => 'string', 'grant_types' => 'collection', 'confidential' => 'boolean', ]; /** * @throws RandomException|EnvironmentIsBrokenException */ public function __construct(array $attributes = []) { parent::__construct($attributes); $this->client_id = Rand::string(32); $this->client_secret = Rand::string(64); $this->generatePrivateKey(); } public static function byClientId(string $clientId): ?Client { /** @var Client|null $client */ $client = self::where('client_id', $clientId)->first(); return $client; } /** * @return void * @throws EnvironmentIsBrokenException */ private function generatePrivateKey(): void { // generate rsa private and public key pair $config = [ "digest_alg" => "sha256", "private_key_bits" => 4096, "private_key_type" => OPENSSL_KEYTYPE_RSA, ]; $res = openssl_pkey_new($config); openssl_pkey_export($res, $privateKey); $this->private_key = $privateKey; $this->encryption_key = Key::createNewRandomKey()->saveToAsciiSafeString(); } /** * @return HasMany */ public function clientRedirectUris(): HasMany { return $this->hasMany(ClientRedirectUri::class); } /** * @return HasManyThrough */ public function scopes(): HasManyThrough { return $this->hasManyThrough( Scope::class, ClientScope::class, 'client_id', 'id', 'id', 'scope_id' ); } /** * @return HasManyThrough */ public function users(): HasManyThrough { return $this->hasManyThrough( User::class, ClientUser::class, 'client_id', 'id', 'id', 'user_id' ); } /** * @return string */ public function getIdentifier(): string { return $this->id; } /** * @return string */ public function getName(): string { return $this->name; } /** * @return string|array */ public function getRedirectUri(): string|array { return $this->clientRedirectUris->pluck('redirect_uri')->toArray(); } /** * @return bool */ public function isConfidential(): bool { return $this->confidential; } public function getCapabilitiesAttribute(string $capabilities): ClientCapabilities { return ClientCapabilities::fromJson($capabilities); } /** * @throws \JsonException */ public function setCapabilitiesAttribute(ClientCapabilities $capabilities): void { $this->attributes['capabilities'] = $capabilities->toJson(); } /** * @throws BadFormatException * @throws EnvironmentIsBrokenException * @throws \Exception */ public function getAuthorizationServer(): AuthorizationServer { $authorizationServer = new AuthorizationServer( new ClientRepository($this), new AccessTokenRepository(), new ScopeRepository(), $this->private_key, Key::loadFromAsciiSafeString($this->encryption_key) ); if (!empty($this->grant_types)) { foreach ($this->grant_types as $grantType) { switch ($grantType) { case 'authorization_code': $grant = new \League\OAuth2\Server\Grant\AuthCodeGrant( new \Siteworxpro\App\OAuth\AuthCodeRepository(), new \Siteworxpro\App\OAuth\RefreshTokenRepository(), new \DateInterval('PT10M') ); $grant->setRefreshTokenTTL(new \DateInterval('P1M')); break; case 'client_credentials': $grant = new \League\OAuth2\Server\Grant\ClientCredentialsGrant(); break; case 'refresh_token': $grant = new \League\OAuth2\Server\Grant\RefreshTokenGrant( new \Siteworxpro\App\OAuth\RefreshTokenRepository() ); $grant->setRefreshTokenTTL(new \DateInterval('P1M')); break; default: continue 2; } $authorizationServer->enableGrantType($grant); } } return $authorizationServer; } public function loginUser(string $username, string $password): ?User { /** @var User|null $user */ $user = $this->users()->where('email', $username)->first(); if (!$user) { return null; } return $user->verifyPassword($password) ? $user : null; } }