Zum Hauptinhalt springen
Bei der OAuth-2.0-Authentifizierung erteilen Nutzer Zugriff auf ihre individuellen Google Sheets. Geeignet für Anwendungen, die mit nutzerspezifischen Daten arbeiten.

Anwendungsfälle

  • Nutzerzentrierte Apps – Nutzer greifen auf ihre eigenen Google Sheets zu
  • Multi-Tenant-Apps – Verschiedene Nutzer verwalten unterschiedliche Spreadsheets
  • Zugriff auf persönliche Daten – Sheets im eigenen Konto der Nutzer lesen/schreiben
  • Desktop- oder Webanwendungen – Nutzerinteraktion möglich

Voraussetzungen

  • Ein Projekt in der Google Cloud Console
  • Google Sheets API und Google Drive API aktiviert
  • Laravel Socialite (empfohlen)

Einrichtung

1

Google Cloud Console konfigurieren

  1. Gehen Sie zur Google Cloud Console.
  2. Wählen Sie ein Projekt aus oder erstellen Sie ein neues.
  3. Navigieren Sie zu APIs & Services > Library.
  4. Aktivieren Sie folgende APIs:
    • Google Sheets API
    • Google Drive API
2

OAuth-2.0-Credentials erstellen

  1. Gehen Sie zu APIs & Services > Credentials.
  2. Klicken Sie auf Create Credentials > OAuth client ID.
  3. Konfigurieren Sie den OAuth-Consent-Screen (nur beim ersten Mal):
    • Setzen Sie den User Type auf External.
    • Füllen Sie die Pflichtfelder aus (App-Name, Support-Mail, Entwickler-Kontakt).
    • Fügen Sie die Scopes hinzu: https://www.googleapis.com/auth/spreadsheets und https://www.googleapis.com/auth/drive.
  4. Wählen Sie als Anwendungstyp Web application.
  5. Fügen Sie die Authorized Redirect URIs hinzu:
    • Entwicklung: http://localhost:8000/auth/google/callback
    • Produktion: https://yourdomain.com/auth/google/callback
  6. Klicken Sie auf Create.
  7. Kopieren Sie Client ID und Client Secret.
3

Laravel-Umgebung konfigurieren

Fügen Sie in der .env hinzu:
GOOGLE_CLIENT_ID=your-client-id-here
GOOGLE_CLIENT_SECRET=your-client-secret-here
GOOGLE_REDIRECT=http://localhost:8000/auth/google/callback
Aktualisieren Sie config/google.php:
'client_id' => env('GOOGLE_CLIENT_ID', ''),
'client_secret' => env('GOOGLE_CLIENT_SECRET', ''),
'redirect_uri' => env('GOOGLE_REDIRECT', ''),
'scopes' => [
    \Google\Service\Sheets::SPREADSHEETS,
    \Google\Service\Drive::DRIVE,
],
'access_type' => 'offline', // Erforderlich für Refresh-Token
'prompt' => 'consent select_account',
4

Laravel Socialite installieren

composer require laravel/socialite
In config/services.php ergänzen:
'google' => [
    'client_id' => env('GOOGLE_CLIENT_ID'),
    'client_secret' => env('GOOGLE_CLIENT_SECRET'),
    'redirect' => env('GOOGLE_REDIRECT'),
],
5

Authentifizierungs-Controller implementieren

// app/Http/Controllers/AuthController.php
<?php

namespace App\Http\Controllers;

use App\Models\User;
use Illuminate\Http\Request;
use Laravel\Socialite\Facades\Socialite;

class AuthController extends Controller
{
    public function redirectToGoogle()
    {
        return Socialite::driver('google')
            ->scopes(config('google.scopes'))
            ->with([
                'access_type' => config('google.access_type'),
                'prompt' => config('google.prompt'),
            ])
            ->redirect();
    }

    public function handleGoogleCallback()
    {
        try {
            $googleUser = Socialite::driver('google')->user();
            
            $user = User::updateOrCreate(
                ['email' => $googleUser->email],
                [
                    'name' => $googleUser->name,
                    'email' => $googleUser->email,
                    'google_access_token' => $googleUser->token,
                    'google_refresh_token' => $googleUser->refreshToken,
                    'google_expires_in' => $googleUser->expiresIn,
                    'google_token_created' => now()->timestamp,
                ]
            );

            auth()->login($user);

            return redirect('/dashboard')->with('success', 'Google-Authentifizierung erfolgreich');
        } catch (\Exception $e) {
            return redirect('/login')
                ->with('error', 'Authentifizierung fehlgeschlagen: ' . $e->getMessage());
        }
    }

    public function logout(Request $request)
    {
        auth()->logout();
        $request->session()->invalidate();
        $request->session()->regenerateToken();

        return redirect('/');
    }
}
6

Routen hinzufügen

// routes/web.php
Route::get('/auth/google', [AuthController::class, 'redirectToGoogle'])
    ->name('google.redirect');
Route::get('/auth/google/callback', [AuthController::class, 'handleGoogleCallback'])
    ->name('google.callback');
Route::post('/logout', [AuthController::class, 'logout'])
    ->name('logout');
7

User-Modell aktualisieren

Migration:
// database/migrations/add_google_tokens_to_users_table.php
Schema::table('users', function (Blueprint $table) {
    $table->text('google_access_token')->nullable();
    $table->text('google_refresh_token')->nullable();
    $table->integer('google_expires_in')->nullable();
    $table->integer('google_token_created')->nullable();
});
User-Modell:
// app/Models/User.php
protected $fillable = [
    'name',
    'email',
    'password',
    'google_access_token',
    'google_refresh_token',
    'google_expires_in',
    'google_token_created',
];

protected $hidden = [
    'password',
    'remember_token',
    'google_access_token',
    'google_refresh_token',
];

public function getGoogleTokenArray(): array
{
    return [
        'access_token' => $this->google_access_token,
        'refresh_token' => $this->google_refresh_token,
        'expires_in' => $this->google_expires_in,
        'created' => $this->google_token_created,
    ];
}

public function hasValidGoogleToken(): bool
{
    return !empty($this->google_access_token) 
        && !empty($this->google_refresh_token);
}
8

Sheets verwenden

use Revolution\Google\Sheets\Facades\Sheets;

public function getSheetData(Request $request)
{
    $user = $request->user();
    
    if (!$user->hasValidGoogleToken()) {
        return redirect()->route('google.redirect');
    }

    try {
        $token = $user->getGoogleTokenArray();

        $values = Sheets::setAccessToken($token)
            ->spreadsheet('user-spreadsheet-id')
            ->sheet('Sheet1')
            ->all();
            
        return view('sheets.data', compact('values'));
    } catch (\Exception $e) {
        // Bei abgelaufenem Token zur erneuten Authentifizierung
        if (str_contains($e->getMessage(), 'invalid_grant') 
            || str_contains($e->getMessage(), 'unauthorized')) {
            return redirect()->route('google.redirect');
        }

        throw $e;
    }
}

Token-Refresh

Das Paket behandelt abgelaufene Tokens automatisch:
$token = [
    'access_token' => $user->google_access_token,
    'refresh_token' => $user->google_refresh_token,
    'expires_in' => $user->google_expires_in,
    'created' => $user->google_token_created,
];

// Bei Ablauf wird automatisch aktualisiert
Sheets::setAccessToken($token)
    ->spreadsheet('id')
    ->sheet('Sheet1')
    ->all();

// Nach dem Refresh das aktualisierte Token abrufen
$updatedToken = Sheets::getAccessToken();
if ($updatedToken) {
    $user->update([
        'google_access_token' => $updatedToken['access_token'],
        'google_token_created' => time(),
    ]);
}

Middleware

Middleware, die eine Google-Authentifizierung verlangt:
// app/Http/Middleware/RequireGoogleAuth.php
<?php

namespace App\Http\Middleware;

use Closure;
use Illuminate\Http\Request;

class RequireGoogleAuth
{
    public function handle(Request $request, Closure $next)
    {
        $user = $request->user();

        if (!$user || !$user->hasValidGoogleToken()) {
            if ($request->expectsJson()) {
                return response()->json(
                    ['error' => 'Google-Authentifizierung erforderlich'], 
                    401
                );
            }

            return redirect()->route('google.redirect');
        }

        return $next($request);
    }
}

Sicherheit

1. Tokenspeicherung

  • Tokens sicher in der Datenbank speichern
  • Die integrierte Verschlüsselung von Laravel verwenden
  • Tokens nicht clientseitig offenlegen

2. Scope-Management

  • Nur die minimal erforderlichen Scopes anfordern
  • Das Prinzip der geringsten Berechtigung anwenden
  • Den Nutzern die benötigten Berechtigungen klar erläutern

3. Fehlerbehandlung

  • Abgelaufene Tokens angemessen behandeln
  • Einen nutzerfreundlichen Ablauf für die erneute Authentifizierung bereitstellen
  • Fehler protokollieren und überwachen

Fehlerbehebung

Häufige Fehler

Fehler „redirect_uri_mismatch”
  • Prüfen Sie, ob die Redirect-URI in der Google Console mit der der Anwendung exakt übereinstimmt.
  • Achten Sie auf den Unterschied zwischen http und https.
  • Prüfen Sie den abschließenden Slash.
Fehler „invalid_grant” oder „unauthorized”
  • Das Token ist abgelaufen und der Refresh ist fehlgeschlagen.
  • Fordern Sie den Nutzer zur erneuten Authentifizierung auf.
  • Prüfen Sie, ob ein Refresh-Token vorhanden ist.
Fehler „access_denied”
  • Der Nutzer hat die Berechtigung verweigert.
  • Reagieren Sie mit einer passenden Meldung.
  • Bieten Sie eine Möglichkeit zur erneuten Authentifizierung.

Test-Route

Route::get('/test-oauth', function (Request $request) {
    $user = $request->user();
    
    if (!$user->hasValidGoogleToken()) {
        return 'Kein Google-Token vorhanden. '
            . '<a href="' . route('google.redirect') . '">'
            . 'Authentifizieren</a>';
    }
    
    try {
        $token = $user->getGoogleTokenArray();
        $sheets = Sheets::setAccessToken($token)->spreadsheetList();
        
        return 'OAuth funktioniert! Anzahl Spreadsheets: ' 
            . count($sheets);
    } catch (\Exception $e) {
        return 'OAuth-Fehler: ' . $e->getMessage();
    }
})->middleware('auth');
Zuletzt geändert am 13. Juli 2026