Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Laravel Passport Social Grant Laravel Package

coderello/laravel-passport-social-grant

Laravel Passport Social Grant lets API clients exchange social network access tokens (such as Facebook, Google, or Apple) for Laravel Passport OAuth tokens, enabling passwordless social login for mobile and SPA apps.

View on GitHub
Deep Wiki
Context7

Getting Started

coderello/laravel-passport-social-grant adds a social grant type to Laravel Passport, letting mobile/native clients trade a third-party provider token (Apple, Google, Facebook…) for a normal Passport access/refresh token pair — no password involved.

  1. composer require coderello/laravel-passport-social-grant (5.x requires a Passport install that's already migrated — run php artisan passport:install if you haven't).
  2. Publish the package config with php artisan vendor:publish --provider="Coderello\SocialGrant\SocialGrantServiceProvider" and skim config/social-grant.php for the grant registration knob.
  3. Create your grant class, e.g. app/Auth/SocialGrant.php, extending Coderello\SocialGrant\SocialGrant and implementing resolveUserByProviderCredentials(). Return a Coderello\SocialGrant\SocialUser wrapping your local user id, or null to reject.
  4. Register the grant with Passport in AuthServiceProvider::boot() using the README snippet for your Passport version, then clear config.
  5. First use case: an iOS app gets an Apple identity token, POSTs grant_type=social&provider=apple&access_token=<token>&client_id=...&client_secret=... to /oauth/token, and receives standard Passport tokens it can use with auth:api routes immediately.

Look first at the package's SocialGrant abstract and the SocialUserResolver contract — that contract is the entire integration surface.

Implementation Patterns

Resolve-or-create the user inside the grant. Keep provider verification (JWKS validation, issuer/audience checks) in your grant or a small ProviderVerifier service, then map provider + provider subject to a local user:

public function resolveUserByProviderCredentials(string $provider, string $providerCredentials, Client $client): ?SocialUser
{
    $identity = $this->verifier->verify($provider, $providerCredentials, $client);

    $user = User::firstOrCreate(
        ['provider' => $provider, 'provider_id' => $identity->sub],
        ['name' => $identity->name, 'email' => $identity->email],
    );

    return new SocialUser($user->getAuthIdentifier());
}

Use the new $client argument for multi-app routing. 5.0.0 hands you the Passport Client being authenticated. This is the clean seam for per-app configuration: pick the Apple client_id/audience per $client->getKey(), restrict which providers a client may use, or segment users by tenant. Reject early (return null) for clients that shouldn't use the social grant.

Scopes behave like any other grant. Scopes defined in AuthServiceProvider via Passport::tokensCan() are granted from the client's configured scopes; pass scope= in the token request if you need to narrow them. Refresh tokens are issued normally, so grant_type=refresh_token works unchanged.

Keep the HTTP call on your side, not the client's. The client should send the raw provider credential; never let the client tell you which local user to log in as (user_id parameters are an auth bypass).

Testing. Feature-test the real endpoint rather than the grant class in isolation — it catches registration mistakes:

$response = $this->postJson('/oauth/token', [
    'grant_type' => 'social',
    'provider' => 'apple',
    'access_token' => 'fake',
    'client_id' => $client->id,
    'client_secret' => $client->secret,
]);

Bind a fake resolver in the container for the verification step so tests stay offline.

Gotchas and Tips

⚠️ 5.0.0 is a breaking change. resolveUserByProviderCredentials() gained a Client $client parameter. Any existing grant class that declares the old two-argument signature will fatal ("Declaration … must be compatible") the moment it's autoloaded. Upgrade checklist:

  • Update every SocialGrant implementation's signature to (string $provider, string $providerCredentials, Client $client) (or a compatible superset — extra optional params are fine, fewer are not).
  • Update mocks/fakes of SocialUserResolver and any unit tests asserting the old arity.
  • Run php -l / PHPStan over app/Auth before deploying; the failure is a hard fatal, not a deprecation.
  • Pin ^4.0 if you can't ship the signature change alongside your Passport upgrade.

Check what $client actually is. Depending on your Passport major it may be the Eloquent Laravel\Passport\Client or the bridge client. Use getKey()/getAttribute() rather than assuming relations are loaded — the model you receive may be unhydrated.

Mobile apps can't keep a secret. A client_secret baked into an app is not a secret. Prefer a public/PKCE client, or proxy the token exchange through your own backend and keep the Passport client confidential.

Treat the provider token as untrusted input. Verify signature, iss, aud, and exp server-side — Apple's identity tokens are JWTs, and Google/Facebook tokens need an introspection call. Skip aud checking and any attacker can replay a token minted for a different app.

Nothing else authenticates the user. The social grant is a password-less path into your user table; add rate limiting on /oauth/token, log grant usage, and consider disabling the grant entirely in environments/clients that don't need it.

Debugging a 400 unsupported_grant_type almost always means the grant wasn't registered in AuthServiceProvider (or config is cached — php artisan config:clear). A 401 invalid_client means your client_id/client_secret don't match oauth_clients, or the client was created with --public. invalid_grant comes from your resolver returning null; log inside the grant to see which check failed.

Extension points. Override the grant's user resolution and exception handling rather than forking the package; the SocialUserResolver contract and SocialUser value object are the intended seams, and the $client parameter is now the right place for per-client policy.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
ignibyte/aic-framework
glavweb/data-schema-bundle
glavweb/datagrid-bundle
tacticmedia/scim-server
uni-method/frame
neika-ai/sdk
adachsoft/php-code-style
pharaonic/laravel-notification-dependencies
beautinow/translug
dev-brainiac/bot-cloaked
octoberrain/html
octoberrain/extension
octoberrain/exception
octoberrain/contracts
adachsoft/api-version-bundle
cgv/localized-resource
noith/settings
kda/laravel-package
kda/filament-dynamic-navigation
bypersoft/signbox