Laravel AT Protocol Client (alpha & unstable)
1<?php
2
3namespace SocialDept\AtpClient\Auth;
4
5use Illuminate\Support\Facades\Http;
6use SocialDept\AtpClient\Data\AccessToken;
7use SocialDept\AtpClient\Data\DPoPKey;
8use SocialDept\AtpClient\Enums\AuthType;
9use SocialDept\AtpClient\Exceptions\AuthenticationException;
10use SocialDept\AtpClient\Http\DPoPClient;
11
12class TokenRefresher
13{
14 public function __construct(
15 protected DPoPClient $dpopClient,
16 protected ClientAssertionManager $clientAssertion,
17 ) {}
18
19 /**
20 * Refresh access token using refresh token.
21 * NOTE: Refresh tokens are single-use!
22 */
23 public function refresh(
24 string $refreshToken,
25 string $pdsEndpoint,
26 DPoPKey $dpopKey,
27 ?string $handle = null,
28 AuthType $authType = AuthType::OAuth,
29 ): AccessToken {
30 return $authType === AuthType::Legacy
31 ? $this->refreshLegacy($refreshToken, $pdsEndpoint, $handle)
32 : $this->refreshOAuth($refreshToken, $pdsEndpoint, $dpopKey, $handle);
33 }
34
35 /**
36 * Refresh OAuth session using /oauth/token endpoint with DPoP.
37 */
38 protected function refreshOAuth(
39 string $refreshToken,
40 string $pdsEndpoint,
41 DPoPKey $dpopKey,
42 ?string $handle,
43 ): AccessToken {
44 $tokenUrl = $pdsEndpoint.'/oauth/token';
45
46 $response = $this->dpopClient->request($pdsEndpoint, $tokenUrl, 'POST', $dpopKey)
47 ->asForm()
48 ->post($tokenUrl, array_merge(
49 $this->clientAssertion->getAuthParams($pdsEndpoint),
50 [
51 'grant_type' => 'refresh_token',
52 'refresh_token' => $refreshToken,
53 ]
54 ));
55
56 if ($response->failed()) {
57 throw new AuthenticationException('Token refresh failed: '.$response->body());
58 }
59
60 return AccessToken::fromResponse($response->json(), $handle, $pdsEndpoint);
61 }
62
63 /**
64 * Refresh legacy session using /xrpc/com.atproto.server.refreshSession endpoint.
65 */
66 protected function refreshLegacy(
67 string $refreshToken,
68 string $pdsEndpoint,
69 ?string $handle,
70 ): AccessToken {
71 $response = Http::withHeader('Authorization', 'Bearer '.$refreshToken)
72 ->withBody('', 'application/json')
73 ->post($pdsEndpoint.'/xrpc/com.atproto.server.refreshSession');
74
75 if ($response->failed()) {
76 throw new AuthenticationException('Token refresh failed: '.$response->body());
77 }
78
79 return AccessToken::fromResponse($response->json(), $handle, $pdsEndpoint);
80 }
81}