Laravel AT Protocol Client (alpha & unstable)
3
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge branch 'dev'

+38 -4
+33 -2
src/Auth/ClientMetadataManager.php
··· 41 41 */ 42 42 public function isLocalhost(): bool 43 43 { 44 - return $this->getClientId() === 'http://localhost'; 44 + return str_starts_with($this->getClientId(), 'http://localhost'); 45 45 } 46 46 47 47 /** ··· 111 111 * 112 112 * In production, points to the package's client-metadata.json endpoint. 113 113 * For localhost detection, checks if app URL contains localhost or .test. 114 + * 115 + * For localhost clients, the client_id includes query parameters for 116 + * redirect_uri and scope since there's no metadata document to fetch. 117 + * 118 + * @see https://atproto.com/specs/oauth#clients 114 119 */ 115 120 protected function generateClientId(): string 116 121 { ··· 119 124 120 125 // Detect local development environments 121 126 if ($this->isLocalDevelopment($host)) { 122 - return 'http://localhost'; 127 + return $this->buildLocalhostClientId(); 123 128 } 124 129 125 130 // Production: point to client metadata endpoint 126 131 $prefix = config('client.oauth.prefix', '/atp/oauth/'); 127 132 128 133 return rtrim($appUrl, '/').rtrim($prefix, '/').'/client-metadata.json'; 134 + } 135 + 136 + /** 137 + * Build localhost client_id with query parameters. 138 + * 139 + * For localhost clients, metadata is passed via query parameters: 140 + * - redirect_uri: The callback URL (using 127.0.0.1) 141 + * - scope: Space-separated list of requested scopes 142 + */ 143 + protected function buildLocalhostClientId(): string 144 + { 145 + $params = []; 146 + 147 + // Add redirect URI 148 + $redirectUris = config('client.client.redirect_uris', []); 149 + if (! empty($redirectUris)) { 150 + $params['redirect_uri'] = $redirectUris[0]; 151 + } else { 152 + $params['redirect_uri'] = 'http://127.0.0.1'; 153 + } 154 + 155 + // Add scopes 156 + $scopes = config('client.client.scopes', ['atproto']); 157 + $params['scope'] = implode(' ', $scopes); 158 + 159 + return 'http://localhost?'.http_build_query($params); 129 160 } 130 161 131 162 /**
+5 -2
src/Auth/OAuthEngine.php
··· 8 8 use SocialDept\AtpClient\Data\DPoPKey; 9 9 use SocialDept\AtpClient\Exceptions\AuthenticationException; 10 10 use SocialDept\AtpClient\Http\DPoPClient; 11 - use SocialDept\AtpResolver\Facades\Resolver; 11 + use SocialDept\Resolver\Facades\Resolver; 12 12 13 13 class OAuthEngine 14 14 { ··· 23 23 */ 24 24 public function authorize( 25 25 string $identifier, 26 - array $scopes = ['atproto', 'transition:generic'], 26 + ?array $scopes = null, 27 27 ?string $pdsEndpoint = null 28 28 ): AuthorizationRequest { 29 + // Use configured scopes if none provided 30 + $scopes = $scopes ?? $this->metadata->getScopes(); 31 + 29 32 // Resolve PDS endpoint 30 33 if (! $pdsEndpoint) { 31 34 $pdsEndpoint = Resolver::resolvePds($identifier);