diff --git a/CHANGELOG.md b/CHANGELOG.md index 2e6733d..66ad9f5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,11 +9,11 @@ adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ### Changed -- **Breaking. Social login moved to `laranail/authkit-social`.** Fifteen classes, the `socials` +- **Breaking. Social login moved to `laranail/authkit-social-login`.** Fifteen classes, the `socials` migration, its factory and the `social` config block left this package. See [UPGRADING.md](UPGRADING.md); `rector-migrate-social.php` codemods the class renames. - The config key moved from `laranail.authkit.social.*` to `laranail.authkit-social.*`, in the new + The config key moved from `laranail.authkit.social.*` to `laranail.authkit-social-login.*`, in the new package's own published file. **Provider env variable names are unchanged** — `AUTHKIT_GOOGLE_CLIENT_ID` and the rest keep working, because renaming them would break deployed `.env` files with credentials silently resolving to null. @@ -22,10 +22,14 @@ adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). All three were used only by social code, so the core no longer pulls Socialite into applications that never touch social login. - The `laranail::authkit-social-migrations` publish tag is unchanged, but is now published by the - new package rather than this one. The migration filename is unchanged, so an application that has + The `laranail::authkit-social-login-migrations` publish tag is now published by the new package + rather than this one. The migration filename is unchanged, so an application that has already run it will not run it again. +- Core documentation now describes social login as a separate package and points to its current + guide, config key, and publish tags. The core provider contracts are documented as extension + seams, not as shipped Socialite behavior. + - `testbench.yaml` no longer declares `Workbench\Database\Seeders\DatabaseSeeder` or `workbench/database/migrations`. Neither existed. `composer.json` dropped the matching autoload-dev root for the same reason. diff --git a/README.md b/README.md index 661b784..ac551b5 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,6 @@ Headless authentication for Laravel 13+. Ships the REST API; no views and no web - **Fortify-backed** — password reset, profile updates, password updates, email verification, passkeys, login throttling - **Sanctum-ready** — API token issuance via `IssueTokenForUser` -- **Social login** — Google, Apple, X, LinkedIn, PayPal via Socialite - **Composable** — separate actions for credential check vs session login ## Requirements @@ -54,7 +53,7 @@ Full documentation: (bool) env('AUTHKIT_SOCIAL_ENABLED', default: true), - - 'google' => [ - 'client_id' => env('AUTHKIT_GOOGLE_CLIENT_ID'), - 'client_secret' => env('AUTHKIT_GOOGLE_CLIENT_SECRET'), - 'redirect' => env('AUTHKIT_GOOGLE_REDIRECT'), - 'scopes' => ['openid', 'profile', 'email'], - ], - // apple, x, linkedin, paypal ... -``` - Remove `passkeys` from `laranail.authkit.fortify.features` to disable Fortify's passkey routes. Auth Kit only enables and configures Fortify; passkey ceremonies, responses, and persistence remain provided by Fortify and `laravel/passkeys`. ### Security defaults - Two-factor authentication is not enabled by default. MFA is still work in progress. -- Social sign-in only provisions or auto-links an account when the provider asserts it verified the address. Every shipped provider does, through its own claim: Google, Apple, LinkedIn, and PayPal return `email_verified`, X returns `confirmed_email`. Facebook is not shipped, because it asserts nothing. - Before production, configure HTTPS, secure session cookies, a working mail transport, and Turnstile keys when bot protection is enabled. -- PayPal uses sandbox mode by default. Set `AUTHKIT_PAYPAL_SANDBOX_MODE=false` with production PayPal credentials before enabling it in production. ## Passkeys @@ -191,10 +166,6 @@ The application client should use Fortify's `/passkeys/login/options`, `/passkey | `IssueTokenForUser` | Issue Sanctum personal access token, returns `TokenResult` | | `CheckEmailExists` | Check if email is registered | | `FindUserByEmail` | Retrieve user by email | -| `ResolveSocialIdentity` | Safe social identity → user resolution (verified-email check) | -| `SocialRedirectAction` | Generate OAuth redirect URL, returns `SocialRedirectResult` | -| `SocialCallbackAction` | Handle OAuth callback via `ResolveSocialIdentity` | -| `CreateSocialAccountAction` | Create social account record via polymorphic relation | ## Result types @@ -214,12 +185,6 @@ Check with `$result->isPassed()` or match on `$result->status` (`AuthStatus::Pas new TokenResult(user: $user, token: $token) ``` -**`SocialRedirectResult`** — returned by `SocialRedirectAction`: - -```php -new SocialRedirectResult(url: $url) -``` - ## Abstract controllers Extend these to wire up your own routes. JSON responses are handled automatically. @@ -230,38 +195,11 @@ Extend these to wire up your own routes. JSON responses are handled automaticall | `AbstractCheckEmailExistsController` | `respond()` | | `AbstractLogoutController` | `loggedOut()` | | `AbstractRegisterController` | `registered()` | -| `AbstractSocialRedirectController` | `redirect()` | -| `AbstractSocialCallbackController` | `passed()`, `failed()` | - ## Social login -`ResolveSocialIdentity` implements verified-email linking to prevent account takeover: - -1. Existing social account → returns user (updates tokens) -2. Authenticated user → links social account -3. Unverified email match → **returns null** (prevents takeover) -4. Verified email match → auto-links -5. No match → creates new user + social record - -### Social model - -Add to your `User` model: - -```php -use Simtabi\Laranail\AuthKit\Social\Models\Social; -use Illuminate\Database\Eloquent\Relations\MorphMany; - -public function socials(): MorphMany -{ - return $this->morphMany(Social::class, 'socialable'); -} -``` - -Publish the migration: - -```bash -php artisan vendor:publish --tag=laranail::authkit-social-migrations -``` +Social login is maintained in [`laranail/authkit-social-login`](https://github.com/laranail/authkit-social-login), +which extends this package. See its [social login guide](https://github.com/laranail/authkit-social-login/blob/main/docs/social-login.md) +for installation, providers, routes, persistence, and account-linking behavior. ## Usage @@ -295,30 +233,15 @@ return response()->json([ ]); ``` -### Social redirect + callback - -```php -$redirect = app(SocialRedirectAction::class)->execute( - request: $request, -); - -return redirect($redirect->url); - -// Callback: -$result = app(SocialCallbackAction::class)->execute( - request: $request, - guard: 'web', -); -``` - ## Sister packages | Package | Role | |---|---| | [`laranail/authkit`](https://github.com/laranail/authkit) | Headless core — actions, contracts, result objects, REST API | | [`laranail/authkit-preset`](https://github.com/laranail/authkit-preset) | Blade scaffolding on top of the core | +| [`laranail/authkit-social-login`](https://github.com/laranail/authkit-social-login) | Social login through Socialite | | `laranail/authkit-sso` | SAML 2.0 and OIDC single sign-on | -| `laranail/authkit-oauth` | OAuth and social identity | +| `laranail/authkit-oauth` | OAuth server, apps and scopes | | `laranail/authkit-tenancy` | Multi-tenancy | | `laranail/authkit-ldap` | LDAP and Active Directory | diff --git a/UPGRADING.md b/UPGRADING.md index 3305086..594df53 100644 --- a/UPGRADING.md +++ b/UPGRADING.md @@ -2,16 +2,16 @@ Breaking changes, and what to do about them. Versions not listed here need no action. -## Social login moved to `laranail/authkit-social` +## Social login moved to `laranail/authkit-social-login` Social login is no longer part of this package. Fifteen classes, the `socials` migration, the factory and the `social` config block now live in -[`laranail/authkit-social`](https://github.com/laranail/authkit-social). +[`laranail/authkit-social-login`](https://github.com/laranail/authkit-social-login). **Most of the mechanical part is a codemod:** ```bash -composer require laranail/authkit-social +composer require laranail/authkit-social-login vendor/bin/rector process app/ --config vendor/laranail/authkit/rector-migrate-social.php ``` @@ -24,19 +24,19 @@ the `require`: ```json "repositories": [ - { "type": "vcs", "url": "https://github.com/laranail/authkit-social.git" } + { "type": "vcs", "url": "https://github.com/laranail/authkit-social-login.git" } ], "require": { - "laranail/authkit-social": "^0.1" + "laranail/authkit-social-login": "^0.1" } ``` ### 2. The config key moved -`laranail.authkit.social.*` → `laranail.authkit-social.*`, in its own published file. +`laranail.authkit.social.*` → `laranail.authkit-social-login.*`, in its own published file. ```bash -php artisan vendor:publish --tag=laranail::authkit-social-config +php artisan vendor:publish --tag=laranail::authkit-social-login-config ``` **Your `.env` does not change.** `AUTHKIT_GOOGLE_CLIENT_ID` and every other provider variable keep @@ -47,8 +47,8 @@ If you published `config/laranail/authkit.php`, delete its `social` block; nothi ### 3. The migration publish tag now comes from the new package -`laranail::authkit-social-migrations` is unchanged as a tag, but it is published by -`laranail/authkit-social` rather than by the core. **The migration filename is unchanged**, so an +`laranail::authkit-social-login-migrations` is published by `laranail/authkit-social-login` rather +than by the core. **The migration filename is unchanged**, so an application that already ran it will not run it again. ### 4. Class names @@ -79,4 +79,4 @@ and the file parses cleanly, so the failure only appears when the class is loade `laravel/socialite`, `socialiteproviders/manager` and `laranail/enumerator` are no longer required by this package. If your application used them directly, require them yourself — installing -`laranail/authkit-social` also brings all three back transitively. +`laranail/authkit-social-login` also brings all three back transitively. diff --git a/docs/architecture.md b/docs/architecture.md index 937b58d..6c0ba8e 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -9,7 +9,7 @@ laranail/authkit Simtabi\Laranail\AuthKit\ this package — laranail/authkit-preset Simtabi\Laranail\AuthKit\Preset\ Blade scaffolding laranail/authkit-sso Simtabi\Laranail\AuthKit\Sso\ SAML and OIDC laranail/authkit-oauth Simtabi\Laranail\AuthKit\OAuth\ OAuth server, apps and scopes -laranail/authkit-social Simtabi\Laranail\AuthKit\Social\ social login (Socialite) +laranail/authkit-social-login Simtabi\Laranail\AuthKit\Social\ social login (Socialite) laranail/authkit-tenancy Simtabi\Laranail\AuthKit\Tenancy\ multi-tenancy laranail/authkit-ldap Simtabi\Laranail\AuthKit\Ldap\ LDAP and Active Directory ``` @@ -50,8 +50,8 @@ The sibling packages exist only if these are real. Each is a container-bound con | Seam | Purpose | Consumers | |---|---|---| -| `ResolveIdentityInterface` | One linking-and-provisioning path for social, SAML, OIDC and directory sign-in, including the verified-identity guard | all | -| `IdentityProviderRegistryInterface` | A registry a sibling pushes a provider into, replacing a closed enum as the universe of providers | oauth, sso | +| `SocialIdentityProviderInterface` | Describes a social identity provider to the social-login package and provider registry | social-login | +| `IdentityProviderRegistryInterface` | A registry a sibling pushes a provider into, replacing a closed enum as the universe of providers | social-login, oauth, sso | | `IssueTokenForUserInterface` | Token issuance, with ability scoping and expiry | all | | `TenantResolverInterface` | Resolves the active tenant; identity tables carry a nullable tenant key | tenancy | | `DirectoryResolverInterface` | Resolves and syncs a directory entry to a local user | ldap | @@ -61,12 +61,9 @@ The sibling packages exist only if these are real. Each is a container-bound con first sibling is written. A sub-package that has to edit the core to do its job is not extending the core, it is forking it. -## Why social login refuses an unverified email - -`ResolveSocialIdentity` will link an external identity to an existing local account only when the -provider asserts the email is verified. Without that check, any provider returning an -attacker-controlled address is an account-takeover path. The guard belongs in the shared resolution -seam so SAML, OIDC and LDAP inherit it rather than each re-deriving it. +Social-provider account linking and verified-email checks are implemented by +[`laranail/authkit-social-login`](https://github.com/laranail/authkit-social-login). The core exposes +the provider contract and registry that package uses; it does not implement Socialite flows. --- diff --git a/docs/configuration.md b/docs/configuration.md index 6d5c714..ccea2f8 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -8,7 +8,7 @@ php artisan vendor:publish --tag=laranail::authkit-config Set `AUTHKIT_GUARD` to the application's intended guard. The `laranail.authkit.fortify.features` list enables Fortify capabilities individually: `reset-passwords`, `update-profile-information`, `update-passwords`, `email-verification`, and `passkeys`. Removing an item prevents Auth Kit from enabling that capability; remove corresponding application routes and UI too. -Credential throttling is controlled by `AUTHKIT_RATE_LIMIT_MAX_ATTEMPTS` and `AUTHKIT_RATE_LIMIT_DECAY_MINUTES`, defaulting to five attempts per minute. Social credentials, callbacks, and enabled providers are configured in `laranail.authkit-social`; see [social login](https://github.com/laranail/authkit-social/blob/main/docs/social-login.md) for provider settings. +Credential throttling is controlled by `AUTHKIT_RATE_LIMIT_MAX_ATTEMPTS` and `AUTHKIT_RATE_LIMIT_DECAY_MINUTES`, defaulting to five attempts per minute. Social credentials, callbacks, and enabled providers belong to [`laranail/authkit-social-login`](https://github.com/laranail/authkit-social-login); see its [social login guide](https://github.com/laranail/authkit-social-login/blob/main/docs/social-login.md). --- diff --git a/docs/email-verification.md b/docs/email-verification.md index 0344120..6d262ce 100644 --- a/docs/email-verification.md +++ b/docs/email-verification.md @@ -18,7 +18,7 @@ Auth Kit provides headless controller bases for the verification lifecycle: The application owns route registration, presentation, redirects, and mail configuration. The user model must implement Laravel's `MustVerifyEmail` contract for verification notifications and state changes to apply. Use Laravel's signed URL and `verified` middleware on the verification endpoint and routes that require a verified address. A profile email change for such a user clears its verification timestamp and sends a new notification. -Social login has its own verified-email rules. See [Social login](https://github.com/laranail/authkit-social/blob/main/docs/social-login.md) before enabling automatic social-account linking. +Social login has separate verified-email rules. See the [`laranail/authkit-social-login` guide](https://github.com/laranail/authkit-social-login/blob/main/docs/social-login.md) before enabling automatic social-account linking. --- diff --git a/docs/installation.md b/docs/installation.md index cbf0292..b631407 100644 --- a/docs/installation.md +++ b/docs/installation.md @@ -39,11 +39,14 @@ key the package merges its defaults into. Publish only what the features you enable actually need: ```bash -php artisan vendor:publish --tag=laranail::authkit-social-migrations php artisan vendor:publish --tag=laranail::authkit-passkey-migrations php artisan migrate ``` +Social account migrations are published by [`laranail/authkit-social-login`](https://github.com/laranail/authkit-social-login), +not by this package. Install that package and follow its [installation guide](https://github.com/laranail/authkit-social-login/blob/main/docs/installation.md) +if your application enables social login. + ## For a Blade UI This package is headless by design: no views, no web routes, and no Blade layer. It does ship the diff --git a/docs/security.md b/docs/security.md index 385c251..3c7e755 100644 --- a/docs/security.md +++ b/docs/security.md @@ -2,7 +2,7 @@ Review the published `config/laranail/authkit.php` before production. Set the intended guard and user model, keep credential rate limits enabled, and configure HTTPS, secure session cookies, CSRF protection, trusted hosts/proxies, and a working mail transport in the consuming Laravel application. -Auth Kit's implemented safeguards are credential throttling by email, IP, and guard; session regeneration on login; session invalidation and CSRF-token regeneration on logout; verified-email-only guest social linking for trusted providers; uniqueness of provider identities; reset/password-change revocation of personal tokens; and password-change invalidation of other compatible guard sessions. They complement—not replace—Laravel's application and deployment security configuration. +Auth Kit's implemented safeguards are credential throttling by email, IP, and guard; session regeneration on login; session invalidation and CSRF-token regeneration on logout; reset/password-change revocation of personal tokens; and password-change invalidation of other compatible guard sessions. They complement—not replace—Laravel's application and deployment security configuration. Social account-linking safeguards are provided by [`laranail/authkit-social-login`](https://github.com/laranail/authkit-social-login); see its [social login guide](https://github.com/laranail/authkit-social-login/blob/main/docs/social-login.md). Turnstile support is opt-in: @@ -14,7 +14,7 @@ TURNSTILE_SECRET_KEY= The configured challenge input is `cf-turnstile-response`. The rule is applied during Auth Kit user creation; attach `ValidateTurnstile` or `TurnstileRule` deliberately to other application-owned endpoints. Protect only routes where a challenge is appropriate, verify the callback server-side, and never treat the browser response as sufficient on its own. -Two-factor authentication is not enabled by default; MFA remains work in progress. Review the [social linking rules](social-login.md#identity-resolution-and-account-linking-safety) and [passkey origin requirements](passkeys.md#relying-party-and-browser-client) before deploying either feature. See [configuration](configuration.md) for feature and guard settings, and [testing](testing.md) for validation guidance. +Two-factor authentication is not enabled by default; MFA remains work in progress. Review the [passkey origin requirements](passkeys.md#relying-party-and-browser-client) before deploying passkeys. See [configuration](configuration.md) for feature and guard settings, and [testing](testing.md) for validation guidance. --- diff --git a/docs/testing.md b/docs/testing.md index d2a8d29..160dbe5 100644 --- a/docs/testing.md +++ b/docs/testing.md @@ -7,7 +7,7 @@ composer test composer lint ``` -The feature suite covers credentials, registration, logout, resets, profile and password updates, social identity handling, passkeys, tokens, and Turnstile behavior. In the consuming application, test application-owned routes, response overrides, middleware, mail delivery, the configured guard, and external-provider callbacks. +The feature suite covers credentials, registration, logout, resets, profile and password updates, passkeys, tokens, and Turnstile behavior. Social identity handling and provider callbacks are tested by [`laranail/authkit-social-login`](https://github.com/laranail/authkit-social-login). In the consuming application, test application-owned routes, response overrides, middleware, mail delivery, and the configured guard. --- diff --git a/src/Contracts/IdentityProviderRegistryInterface.php b/src/Contracts/IdentityProviderRegistryInterface.php index 6090cf0..fe12658 100644 --- a/src/Contracts/IdentityProviderRegistryInterface.php +++ b/src/Contracts/IdentityProviderRegistryInterface.php @@ -9,11 +9,10 @@ /** * The seam through which a sub-package adds an identity provider. * - * laranail/authkit-sso and laranail/authkit-oauth need to contribute providers -- an Okta tenant, - * a SAML IdP, a customer's OIDC endpoint -- without editing this package. The built-in social - * providers stay a closed enum, because an exhaustive match is what forces an explicit decision - * when one is added there; this registry is the equivalent forcing function for providers that - * arrive from outside, since IdentityProvider requires its verification flag to be stated. + * Sibling packages contribute providers -- an Okta tenant, a SAML IdP, or a customer's OIDC endpoint -- + * without editing this package. The social-login package supplies its own built-in provider enum; + * this registry handles providers contributed by packages or applications. IdentityProvider + * requires its email-verification behavior to be stated explicitly. */ interface IdentityProviderRegistryInterface { diff --git a/src/Contracts/SocialIdentityProviderInterface.php b/src/Contracts/SocialIdentityProviderInterface.php index 6da5cc5..42984cb 100644 --- a/src/Contracts/SocialIdentityProviderInterface.php +++ b/src/Contracts/SocialIdentityProviderInterface.php @@ -7,10 +7,9 @@ /** * What identity resolution needs to know about a provider, whoever supplied it. * - * The built-in social providers are a closed enum, because an exhaustive match is what forces an - * explicit decision when one is added. Providers contributed by a sub-package arrive as - * IdentityProvider objects instead. Both answer the same two questions, so the resolution path - * takes this interface and does not care which it was handed. + * The social-login package supplies its built-in providers as an enum; other packages can + * contribute IdentityProvider objects. Both implement this contract so shared identity-provider + * tooling can use them without depending on either implementation. */ interface SocialIdentityProviderInterface {