> ## Documentation Index
> Fetch the complete documentation index at: https://kawax.biz/llms.txt
> Use this file to discover all available pages before exploring further.

# Laravel Sanctum (API-Token-Authentifizierung)

> Wie Sie mit Laravel Sanctum API-Token-Authentifizierung und SPA-Authentifizierung implementieren. Von der Installation bis zur praktischen Nutzung.

## Was ist Sanctum

Laravel Sanctum ist ein schlankes Authentifizierungspaket für SPAs (Single Page Applications), mobile Apps und einfache APIs. Ohne OAuth-Komplexität lassen sich pro Benutzer mehrere API-Tokens ausstellen und verwalten.

Sanctum löst zwei Probleme:

| Authentifizierungsmodus         | Mechanismus                            | Typische Anwendung                       |
| ------------------------------- | -------------------------------------- | ---------------------------------------- |
| **API-Token-Authentifizierung** | Header `Authorization: Bearer <token>` | Mobile Apps, Drittanbieter-Integrationen |
| **SPA-Authentifizierung**       | Session-Cookie + CSRF-Schutz           | Eigenes Frontend (Vue/React usw.)        |

<Info>
  Für ein eigenes SPA, das die API aufruft, verwenden Sie die SPA-Authentifizierung. Für mobile Apps oder Dritte, die die API nutzen, die API-Token-Authentifizierung. Sie können auch nur einen der beiden Modi verwenden.
</Info>

### Passport vs. Sanctum

|                  | Sanctum                  | Passport                        |
| ---------------- | ------------------------ | ------------------------------- |
| **Komplexität**  | Einfach                  | Vollständiger OAuth2            |
| **Geeignet für** | Eigenes SPA, mobile Apps | OAuth-Provider für externe Apps |
| **Token-Typ**    | Personal Access Token    | OAuth2-Access-Token             |

Wenn Sie als OAuth2-Provider für externe Dienste auftreten müssen, wählen Sie Passport. Für die meisten Anwendungen genügt Sanctum.

***

## Installation und Konfiguration

### Installation

Ein einziger Artisan-Befehl richtet Sanctum ein.

```shell theme={null}
php artisan install:api
```

Dabei geschieht automatisch:

* Installation des Pakets `laravel/sanctum`
* Veröffentlichung der Migration für die Tabelle `personal_access_tokens`
* Ausführung der Migration

### Trait `HasApiTokens` hinzufügen

Ergänzen Sie im `User`-Modell das Trait `HasApiTokens`.

```php theme={null}
// app/Models/User.php

use Laravel\Sanctum\HasApiTokens;

class User extends Authenticatable
{
    use HasApiTokens, HasFactory, Notifiable;
}
```

Jetzt stehen Methoden wie `$user->createToken()` und Beziehungen wie `$user->tokens` zur Verfügung.

***

## API-Token-Authentifizierung

### Token-Ablauf

```mermaid theme={null}
sequenceDiagram
    participant Client
    participant API as Laravel-API
    participant DB as Datenbank

    Client->>API: POST /login (email, password)
    API->>DB: Benutzer authentifizieren
    DB-->>API: Benutzerdaten
    API->>DB: Token erzeugen und speichern (gehasht)
    API-->>Client: plainTextToken zurückgeben

    Note over Client: Token speichern

    Client->>API: GET /api/user<br>Authorization: Bearer <token>
    API->>DB: Token abgleichen (SHA-256)
    DB-->>API: Authentifizierter Benutzer
    API-->>Client: Antwort
```

### Token ausstellen

Mit `createToken()` stellen Sie einen Token aus. Über die Eigenschaft `plainTextToken` erhalten Sie den Klartext-Token. **Der Klartext-Token wird nicht in der Datenbank gespeichert** – geben Sie ihn dem Benutzer unmittelbar nach der Erstellung zurück.

```php theme={null}
use Illuminate\Http\Request;

Route::post('/tokens/create', function (Request $request) {
    $token = $request->user()->createToken($request->token_name);

    return ['token' => $token->plainTextToken];
})->middleware('auth');
```

In der Datenbank wird der Token als SHA-256-Hash abgelegt.

### Scopes (Abilities) setzen

Durch Abilities (Scopes) grenzen Sie die Operationen ein, die mit einem Token möglich sind.

```php theme={null}
// Token mit Scopes ausstellen
$token = $user->createToken('mobile-app', ['server:update', 'server:read']);

return $token->plainTextToken;
```

Innerhalb der Request-Verarbeitung prüfen Sie die Scopes.

```php theme={null}
if ($request->user()->tokenCan('server:update')) {
    // Update durchführen
}

if ($request->user()->tokenCant('server:update')) {
    abort(403);
}
```

#### Scopes per Middleware prüfen

Registrieren Sie Middleware-Aliase in `bootstrap/app.php`.

```php theme={null}
use Laravel\Sanctum\Http\Middleware\CheckAbilities;
use Laravel\Sanctum\Http\Middleware\CheckForAnyAbility;

->withMiddleware(function (Middleware $middleware): void {
    $middleware->alias([
        'abilities' => CheckAbilities::class,  // alle Abilities
        'ability'   => CheckForAnyAbility::class, // mindestens eine Ability
    ]);
})
```

Und binden Sie sie an Routen.

```php theme={null}
// Nur Tokens mit check-status UND place-orders
Route::get('/orders', function () {
    // ...
})->middleware(['auth:sanctum', 'abilities:check-status,place-orders']);

// Tokens mit check-status ODER place-orders
Route::get('/orders', function () {
    // ...
})->middleware(['auth:sanctum', 'ability:check-status,place-orders']);
```

### Token-Gültigkeit

Standardmäßig laufen Sanctum-Tokens nie ab. In `config/sanctum.php` legen Sie unter `expiration` eine Gültigkeit in Minuten fest.

```php theme={null}
// config/sanctum.php
'expiration' => 525600, // 365 Tage (Minuten)
```

Auch pro Token lässt sich eine Gültigkeit angeben.

```php theme={null}
$token = $user->createToken(
    'token-name',
    ['*'],
    now()->addWeeks(1) // läuft in 1 Woche ab
)->plainTextToken;
```

Wenn Sie eine Gültigkeit setzen, sollten Sie abgelaufene Tokens regelmäßig entfernen.

```php theme={null}
use Illuminate\Support\Facades\Schedule;

Schedule::command('sanctum:prune-expired --hours=24')->daily();
```

### Tokens widerrufen

```php theme={null}
// Alle Tokens entfernen
$user->tokens()->delete();

// Den im aktuellen Request verwendeten Token entfernen
$request->user()->currentAccessToken()->delete();

// Bestimmten Token entfernen
$user->tokens()->where('id', $tokenId)->delete();
```

***

## SPA-Authentifizierung

Die SPA-Authentifizierung verwendet Session-Cookies und braucht keine Token-Ausstellung. Sie eignet sich, wenn Ihre eigene Frontend-Anwendung (Vue, React, Next.js …) die API aufruft.

<Warning>
  Für die SPA-Authentifizierung müssen SPA und API dieselbe Top-Level-Domain haben (unterschiedliche Subdomains sind erlaubt). Zudem sollten Requests die Header `Accept: application/json` und `Referer` bzw. `Origin` enthalten.
</Warning>

### Sanctum-Middleware aktivieren

Aktivieren Sie in `bootstrap/app.php` `statefulApi()`.

```php theme={null}
->withMiddleware(function (Middleware $middleware): void {
    $middleware->statefulApi();
})
```

### First-Party-Domains konfigurieren

Tragen Sie die SPA-Domains in `config/sanctum.php` unter `stateful` ein.

```php theme={null}
// config/sanctum.php
'stateful' => explode(',', env('SANCTUM_STATEFUL_DOMAINS', sprintf(
    '%s%s',
    'localhost,localhost:3000,127.0.0.1,127.0.0.1:8000,::1',
    Sanctum::currentApplicationUrlWithPort()
))),
```

### CORS konfigurieren

Wenn die API von einer anderen Subdomain aufgerufen wird, benötigen Sie CORS-Einstellungen.

```shell theme={null}
php artisan config:publish cors
```

Setzen Sie in `config/cors.php` `supports_credentials` auf `true`.

```php theme={null}
// config/cors.php
'supports_credentials' => true,
```

Auch das Frontend-`axios` muss angepasst werden.

```js theme={null}
// resources/js/bootstrap.js
axios.defaults.withCredentials = true;
axios.defaults.withXSRFToken = true;
```

Und vergessen Sie nicht die Cookie-Domain.

```php theme={null}
// config/session.php
'domain' => '.example.com', // führender Punkt
```

### Ablauf der Anmeldung aus dem SPA

```mermaid theme={null}
sequenceDiagram
    participant SPA as SPA-Frontend
    participant API as Laravel-API
    participant Session

    SPA->>API: GET /sanctum/csrf-cookie
    API-->>SPA: XSRF-TOKEN-Cookie setzen

    SPA->>API: POST /login<br>X-XSRF-TOKEN-Header
    API->>Session: Session anlegen
    API-->>SPA: Set-Cookie: laravel_session

    SPA->>API: GET /api/user<br>Cookie: laravel_session
    API->>Session: Session prüfen
    Session-->>API: Authentifizierter Benutzer
    API-->>SPA: Benutzerdaten
```

<Steps>
  <Step title="CSRF-Cookie holen">
    Vor dem Login den Endpunkt `/sanctum/csrf-cookie` aufrufen.

    ```js theme={null}
    await axios.get('/sanctum/csrf-cookie');
    ```
  </Step>

  <Step title="Login-Request senden">
    POST-Request an `/login`.

    ```js theme={null}
    await axios.post('/login', {
        email: 'user@example.com',
        password: 'password',
    });
    ```
  </Step>

  <Step title="Authentifizierte Requests">
    Nachfolgende Requests werden automatisch über das Session-Cookie authentifiziert.

    ```js theme={null}
    const response = await axios.get('/api/user');
    console.log(response.data); // authentifizierter Benutzer
    ```
  </Step>
</Steps>

***

## Authentifizierte Routen schützen

Mit der Middleware `auth:sanctum` erhalten unauthentifizierte Requests `401 Unauthorized`. Beide Modi (Token- und SPA-Auth) werden von dieser Middleware abgedeckt.

```php theme={null}
use Illuminate\Http\Request;

// Einzelne Route schützen
Route::get('/user', function (Request $request) {
    return $request->user();
})->middleware('auth:sanctum');

// Routengruppe schützen
Route::middleware('auth:sanctum')->group(function () {
    Route::get('/profile', [ProfileController::class, 'show']);
    Route::put('/profile', [ProfileController::class, 'update']);
    Route::get('/posts', [PostController::class, 'index']);
});
```

***

## Praxisbeispiel: Login-API mit Token-Rückgabe

Beispiel für die API-Token-Authentifizierung in einer mobilen App.

<Steps>
  <Step title="Login-Endpunkt anlegen">
    ```php theme={null}
    // routes/api.php

    use App\Models\User;
    use Illuminate\Http\Request;
    use Illuminate\Support\Facades\Hash;
    use Illuminate\Validation\ValidationException;

    Route::post('/sanctum/token', function (Request $request) {
        $request->validate([
            'email'       => ['required', 'email'],
            'password'    => ['required'],
            'device_name' => ['required', 'string'],
        ]);

        $user = User::where('email', $request->email)->first();

        if (! $user || ! Hash::check($request->password, $user->password)) {
            throw ValidationException::withMessages([
                'email' => ['Die angegebenen Anmeldedaten sind ungültig.'],
            ]);
        }

        return response()->json([
            'token' => $user->createToken($request->device_name)->plainTextToken,
        ]);
    });
    ```
  </Step>

  <Step title="Authentifizierte Routen">
    ```php theme={null}
    // routes/api.php

    Route::middleware('auth:sanctum')->group(function () {
        // Aktuellen Benutzer zurückgeben
        Route::get('/user', function (Request $request) {
            return $request->user();
        });

        // Aktuellen Token widerrufen (Logout)
        Route::post('/logout', function (Request $request) {
            $request->user()->currentAccessToken()->delete();

            return response()->json(['message' => 'Abgemeldet.']);
        });

        // Von allen Geräten abmelden
        Route::post('/logout/all', function (Request $request) {
            $request->user()->tokens()->delete();

            return response()->json(['message' => 'Von allen Geräten abgemeldet.']);
        });
    });
    ```
  </Step>

  <Step title="Aus dem Client senden">
    ```js theme={null}
    // Login
    const { data } = await axios.post('/api/sanctum/token', {
        email: 'user@example.com',
        password: 'password',
        device_name: 'My iPhone',
    });

    const token = data.token;

    // Authentifizierter Request
    const response = await axios.get('/api/user', {
        headers: {
            Authorization: `Bearer ${token}`,
        },
    });
    ```
  </Step>
</Steps>

***

## Tests

In Sanctum-Tests authentifizieren Sie mit `Sanctum::actingAs()` und geben die zu prüfenden Abilities an.

<Tabs>
  <Tab title="Pest">
    ```php theme={null}
    use App\Models\User;
    use Laravel\Sanctum\Sanctum;

    test('Aufgabenliste abrufen', function () {
        Sanctum::actingAs(
            User::factory()->create(),
            ['view-tasks']
        );

        $response = $this->get('/api/tasks');

        $response->assertOk();
    });

    test('Zugriff mit Token, der alle Abilities besitzt', function () {
        Sanctum::actingAs(
            User::factory()->create(),
            ['*']
        );

        $response = $this->get('/api/tasks');

        $response->assertOk();
    });
    ```
  </Tab>

  <Tab title="PHPUnit">
    ```php theme={null}
    use App\Models\User;
    use Laravel\Sanctum\Sanctum;

    public function test_task_list_can_be_retrieved(): void
    {
        Sanctum::actingAs(
            User::factory()->create(),
            ['view-tasks']
        );

        $response = $this->get('/api/tasks');

        $response->assertOk();
    }
    ```
  </Tab>
</Tabs>

***

## Zusammenfassung

<AccordionGroup>
  <Accordion title="Installationsschritte">
    ```shell theme={null}
    # Sanctum installieren und migrieren
    php artisan install:api
    ```

    Trait `HasApiTokens` im User-Modell:

    ```php theme={null}
    use Laravel\Sanctum\HasApiTokens;

    class User extends Authenticatable
    {
        use HasApiTokens, HasFactory, Notifiable;
    }
    ```
  </Accordion>

  <Accordion title="Häufig verwendete APIs">
    ```php theme={null}
    // Token ausstellen
    $token = $user->createToken('token-name')->plainTextToken;

    // Mit Scopes ausstellen
    $token = $user->createToken('token-name', ['read', 'write'])->plainTextToken;

    // Scope prüfen
    $user->tokenCan('read');   // true/false
    $user->tokenCant('write'); // true/false

    // Tokens widerrufen
    $user->tokens()->delete();                        // alle
    $request->user()->currentAccessToken()->delete(); // aktueller Token
    $user->tokens()->where('id', $id)->delete();      // bestimmter Token
    ```
  </Accordion>

  <Accordion title="API-Token vs. SPA-Authentifizierung wählen">
    * **API-Token-Authentifizierung**: für Clients ohne Session – mobile Apps, Drittanbieter, CLI-Tools.
    * **SPA-Authentifizierung**: für ein eigenes SPA (Vue/React/Next.js) auf derselben Domain/Subdomain. Sicherer und ohne Token-Verwaltung.
  </Accordion>
</AccordionGroup>


## Related topics

- [OAuth-2.0-Authentifizierung - Google Sheets API for Laravel](/de/packages/laravel-google-sheets/oauth.md)
- [Einen MCP-Server mit Laravel bauen](/de/advanced/mcp-server.md)
- [Service-Account-Authentifizierung - Google Sheets API für Laravel](/de/packages/laravel-google-sheets/service-account.md)
- [Laravel Passport (OAuth2-Server-Implementierung)](/de/passport.md)
- [Laravel MCP](/de/mcp.md)
