create([ 'slug' => 'test-tenant', ]); OAuthClient::create([ 'id' => (string) Str::uuid(), 'client_id' => 'tenant-admin-app', 'tenant_id' => $tenant->id, 'redirect_uris' => ['http://localhost/callback'], 'scopes' => ['tenant:read', 'tenant:write'], 'is_active' => true, ]); $codeVerifier = 'unit-test-code-verifier-1234567890'; $codeChallenge = rtrim(strtr(base64_encode(hash('sha256', $codeVerifier, true)), '+/', '-_'), '='); $state = Str::random(10); $response = $this->get('/api/v1/oauth/authorize?' . http_build_query([ 'client_id' => 'tenant-admin-app', 'redirect_uri' => 'http://localhost/callback', 'response_type' => 'code', 'scope' => 'tenant:read tenant:write', 'state' => $state, 'code_challenge' => $codeChallenge, 'code_challenge_method' => 'S256', ])); $response->assertRedirect(); $location = $response->headers->get('Location'); $this->assertNotNull($location); $query = []; parse_str(parse_url($location, PHP_URL_QUERY) ?? '', $query); $authorizationCode = $query['code'] ?? null; $this->assertNotNull($authorizationCode, 'Authorization code should be present'); $this->assertEquals($state, $query['state'] ?? null); $tokenResponse = $this->post('/api/v1/oauth/token', [ 'grant_type' => 'authorization_code', 'code' => $authorizationCode, 'client_id' => 'tenant-admin-app', 'redirect_uri' => 'http://localhost/callback', 'code_verifier' => $codeVerifier, ]); $tokenResponse->assertOk(); $tokenData = $tokenResponse->json(); $this->assertArrayHasKey('access_token', $tokenData); $this->assertArrayHasKey('refresh_token', $tokenData); $this->assertSame('Bearer', $tokenData['token_type']); $meResponse = $this->get('/api/v1/tenant/me', [ 'Authorization' => 'Bearer ' . $tokenData['access_token'], ]); $meResponse->assertOk(); $meResponse->assertJsonFragment([ 'tenant_id' => $tenant->id, 'name' => $tenant->name, ]); $refreshResponse = $this->post('/api/v1/oauth/token', [ 'grant_type' => 'refresh_token', 'refresh_token' => $tokenData['refresh_token'], 'client_id' => 'tenant-admin-app', ]); $refreshResponse->assertOk(); $refreshData = $refreshResponse->json(); $this->assertArrayHasKey('access_token', $refreshData); $this->assertArrayHasKey('refresh_token', $refreshData); $this->assertNotEquals($refreshData['access_token'], $tokenData['access_token']); } }