morphMany(PersonalAccessToken::class, 'tokenable'); } public function currentAccessToken(): ?PersonalAccessToken { return $this->accessToken ?? null; } public function withAccessToken(?PersonalAccessToken $token): static { $this->accessToken = $token; return $this; } /** * Create a new token. * * @param array $abilities * @param array $allowedIps * @return array{token: PersonalAccessToken, plainTextToken: string} */ public function createToken( string $name, array $abilities, ?array $allowedIps = null, ?\DateTimeInterface $expiresAt = null, ?string $description = null, ?int $createdBy = null, ): array { foreach ($abilities as $ability) { if (! TokenAbilities::exists($ability)) { throw new \InvalidArgumentException("Unknown ability: {$ability}"); } } $plain = bin2hex(random_bytes(32)); $token = $this->tokens()->create([ 'name' => $name, 'description' => $description, 'token' => hash('sha256', $plain), 'abilities' => array_values(array_unique($abilities)), 'allowed_ips' => $allowedIps ? array_values(array_filter(array_map('trim', $allowedIps))) : null, 'expires_at' => $expiresAt, 'created_by' => $createdBy, ]); return [ 'token' => $token, 'plainTextToken' => $token->id . '|' . $plain, ]; } }