Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 8 additions & 4 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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.
Expand Down
91 changes: 7 additions & 84 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -54,7 +53,7 @@ Full documentation: <https://opensource.simtabi.com/documentation/laranail/authk

- [Installation](docs/installation.md) — requirements, the repositories block, publishing config
- [Getting started](docs/getting-started.md) — authenticate a user with the core alone
- [Configuration](docs/configuration.md) — guard, rate limits, Fortify features, social credentials
- [Configuration](docs/configuration.md) — guard, rate limits, and Fortify features
- [Architecture](docs/architecture.md) — layering, what is delegated to Fortify, the extension seams
- [Security](docs/security.md) — the guarantees this package makes and the ones it does not
- [Release](docs/release.md) — versioning, tagging, and ordering across the family
Expand All @@ -65,7 +64,7 @@ Full documentation: <https://opensource.simtabi.com/documentation/laranail/authk
- [Password reset](docs/password-reset.md) · [Password updates](docs/password-updates.md)
- [Profile management](docs/profile-management.md) · [Email verification](docs/email-verification.md)
- [Browser sessions](docs/browser-sessions.md) · [API routes](docs/api-routes.md) · [API tokens](docs/api-tokens.md)
- [Social login](https://github.com/laranail/authkit-social/blob/main/docs/social-login.md) · [Passkeys](docs/passkeys.md) · [API tokens](docs/api-tokens.md)
- [Social login](https://github.com/laranail/authkit-social-login/blob/main/docs/social-login.md) · [Passkeys](docs/passkeys.md) · [API tokens](docs/api-tokens.md)

### Project

Expand All @@ -80,10 +79,6 @@ Full documentation: <https://opensource.simtabi.com/documentation/laranail/authk
AUTHKIT_GUARD=web
AUTHKIT_RATE_LIMIT_MAX_ATTEMPTS=5
AUTHKIT_RATE_LIMIT_DECAY_MINUTES=1

AUTHKIT_GOOGLE_CLIENT_ID=
AUTHKIT_GOOGLE_CLIENT_SECRET=
AUTHKIT_GOOGLE_REDIRECT=${APP_URL}/auth/google/callback
```

`config/laranail/authkit.php`:
Expand All @@ -104,32 +99,12 @@ return [
];
```

Social login moved to [`laranail/authkit-social`](https://github.com/laranail/authkit-social) and
carries its own `laranail.authkit-social` config. The provider env variables are unchanged, so an
existing `.env` keeps working:

```php
// config/laranail/authkit-social.php
return [
'enabled' => (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

Expand Down Expand Up @@ -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

Expand All @@ -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.
Expand All @@ -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

Expand Down Expand Up @@ -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 |

Expand Down
20 changes: 10 additions & 10 deletions UPGRADING.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
```

Expand All @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -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.
15 changes: 6 additions & 9 deletions docs/architecture.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
```
Expand Down Expand Up @@ -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 |
Expand All @@ -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.

---

Expand Down
2 changes: 1 addition & 1 deletion docs/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -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).

---

Expand Down
2 changes: 1 addition & 1 deletion docs/email-verification.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.

---

Expand Down
5 changes: 4 additions & 1 deletion docs/installation.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Loading
Loading