Skip to content

OAuth client registration returns empty redirect_uris due to camelCase attribute access #112

@valkyriweb

Description

@valkyriweb

MCP Version

0.3.4

Laravel Version

12.x

PHP Version

8.4

Description

The OAuth client registration endpoint returns redirect_uris: [] (empty array) even though the data is correctly stored in the database. This breaks OAuth 2.1 dynamic client registration for MCP clients like Claude Desktop.

Root Cause

In OAuthRegisterController.php, the response uses camelCase to access Passport Client attributes:

return response()->json([
    // ...
    'grant_types' => $client->grantTypes,      // camelCase
    'redirect_uris' => $client->redirectUris,  // camelCase
    // ...
]);

But Laravel's Attribute accessor system has a quirk: when you access $client->redirectUris (camelCase), it looks for $this->attributes['redirectUris'] to pass as $value to the accessor. Since the actual key is redirect_uris (snake_case), $value is null and the accessor returns an empty array.

Reproduction

$client = new \Laravel\Passport\Client();
$client->setRawAttributes([
    'redirect_uris' => json_encode(['https://example.com']),
]);

$client->redirectUris;    // [] - empty (camelCase BROKEN)
$client->redirect_uris;   // ['https://example.com'] - works (snake_case)

Suggested Fix

Use snake_case attribute access in OAuthRegisterController.php:

return response()->json([
    'client_id' => (string) $client->id,
    'grant_types' => $client->grant_types,      // snake_case
    'response_types' => ['code'],
    'redirect_uris' => $client->redirect_uris,  // snake_case
    'scope' => 'mcp:use',
    'token_endpoint_auth_method' => 'none',
]);

Workaround

Create a custom Passport Client model that reads from $attributes directly instead of relying on $value:

// app/Models/Passport/Client.php
class Client extends \Laravel\Passport\Client
{
    protected function redirectUris(): Attribute
    {
        return Attribute::make(
            get: function (mixed $value, array $attributes): array {
                $redirectUris = $attributes['redirect_uris'] ?? $value;
                // ... rest of accessor logic
            },
        );
    }
}

// AppServiceProvider
Passport::useClientModel(Client::class);

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions