Grundlegende Verwirrung Nuxt 3 / SSR / Stateless und Statefull Authentication / CSRF Protection mit eigener Laravel Sanctum API

FrazeColder

Lt. Commander
Registriert
Okt. 2013
Beiträge
1.718
Hallo zusammen,

ich bin leider ein wenig überfordert, wie ich am besten an mein Problem herangehe. Folgender Fall:

Mein Backend habe ich komplett eigenständig in Laravel geschrieben. Die API dafür basiert auf Laravel Sanctum. Laravel Sanctum kann Authentifizierungen sowohl statefull (Cookie-based) als auch stateless (token-based) durchführen.

Da ich an mein Backend aber auch noch eine Flutter App anbinden möchte und auf der Server-seite nicht sowohl statefull als auch stateless Authentifizierungsmöglichkeiten anbieten möchte, habe ich die gesamte API mittels einer stateless und somit token-based Authentifizierung implementiert.

Dies bedeutet, dass zwischen Client und Server bei jedem Request ein Bearer Token mitgeschickt werden muss.

Standardmäßig läuft der Token, der von Laravel Sanctum ausgegeben wird, niemals ab und ist unendlich lange gültig.
Das möchte ich natürlich nicht und möchte hier später noch ein Ablaufdatum hinzufügen, mit einem Refresh-Token. Vorerst würde ich allerdings erst einmal die einfach stateless token-based Authentifizierung implementieren, bevor ich mich danach noch an die Implementierung eines Refresh-Tokens mache.

Nun zu meinen Fragen:
  1. Ich finde leider keine guten Beispiele oder Anleitungen, um mich in die Implementierung einer Nuxt 3 stateless token-based einzuarbeiten. Ich finde viel zu Nuxt Breeze etc., aber das sind alles statefull und somit Cookie-based Anleitungen. Könnt ihr hier How Tos, Artikel oder Tutorials empfehlen?
  2. Ist mein Vorhaben mit einer Nuxt 3 Applikation vereinbar, welche im SSR-Mode laufen soll?
  3. Könnt ihr ein Package empfehlen, mit dem ich mein Vorhaben umsetzen kann? Ich kenne sidebase/nuxt-auth und hebilicious/authjs-nuxt, allerdings bin ich mir unsicher, ob diese Packages sich dazu eigenen und welches besser für mich passt, weil auch hier, ich kaum Anleitungen finde.
  4. Wenn ich eine stateless token-based Authentifizierung habe, benötigt ich doch keine CSRF protection mehr - richtig? Zumindest nicht mehr auf der Client-Seite, da ja alles stateless ist. Was ich gelesen habe, reicht es, in der CORS.php Datei in Laravel die entsprechenden Domains zu beschränken. Falls ich falsch liege, wie kann ich meine API mit CSRF schützen, wenn ich aber eine stateless token-based Authentifizierung habe?
Viele Grüße
 
Weiß nicht ob es dir hilft, aber hier habe ich eine einfache Token-basierte Lösung.

Refresh habe ich nicht implementiert, aber das sollte nicht all zu schwer sein und SSR sollte grundsätzlich auch gehen.
 
Zuletzt bearbeitet:
Aber in der Laravel Dokumentation steht ja sogar drin, dass Sanctum für SPAs und Mobile Applications ist.

However, if you are attempting to authenticate a single-page application, mobile application, or issue API tokens, you should use Laravel Sanctum. Laravel Sanctum does not support OAuth2; however, it provides a much simpler API authentication development experience.

Wieso sollte ich dann auf OAuth 2.0 setzen?
 
Weil Nuxt SSR und nicht SPA ist. Du hast somit zwei Server-seitige Anwendungen mit derselben Authentifizierung (d.h. gleiche Benutzeraccounts). Dafür ist SSO gedacht.
 
Alles klar, dank dir! Das hilft mir zumindest schon mal weiter.

Aber wie sieht es mit der Flutter App aus?
 
Also ich habe meine API auf Passport umgestellt und bin gerade bei Nuxt dran. Aber mit der Anleitung von Sidebase bekomme ich es nicht wirklich hin.. und beim Googeln finde ich da auch leider nicht wirklich was, weil die das alle immer mit Sanctum machen.

Kennst du noch andere Anleitungen?
 
Woran hapert es denn, gibt es irgendwelche Fehlermeldungen?

Andererseits sehe ich gerade, dass es tatsächlich ein Sanctum-Modul für Nuxt gibt, hätte ich nicht gedacht. Ist dann vielleicht doch die einfachere Option.

Musst halt überlegen, wo die Reise hingeht. Solange die Nuxt-App und die Flutter-App ausschließlich Client des Laravel-Backends sind, dürfte Sanctum ausreichen. Sobald das Bearer-Token auch woanders funktionieren soll, wird es ohne SSO schwierig. Und für OAuth2 gibt es immer eine Library, für Sanctum eher nicht.
 
Punkt 2.3 (hier). Bin überfordert, was ich da eintragen soll und ${passport.baseUrl} wird mir rot markiert, obwohl ich die Variablen in der .env und der nuxt.config.ts Datei gesetzt habe
 
Das sollte eigentlich passen, wie es ist. id und name scheinen frei wählbar zu sein. Wenn ${passport.baseUrl} rot markiert ist, kann das einfach daran liegen, dass Deine IDE nicht nachvollziehen kann, dass die Variablen gesetzt sind. Im Zweifel einfach die Base-URL direkt eintragen. Die müsste http://localhost:8000 oder so lauten, der Dev-Server Deiner Laravel-App halt.

Fehler/Hinweise müssten in den Logs von Nuxt oder Laravel zu finden sein.
 
FrazeColder schrieb:
Punkt 2.3 (hier). Bin überfordert, was ich da eintragen soll und ${passport.baseUrl} wird mir rot markiert, obwohl ich die Variablen in der .env und der nuxt.config.ts Datei gesetzt habe
Hast du die richtigen Abhängigkeiten installiert?

In meiner Sandbox geht es.
 
Danke für eure Antworten! Das hilft mir weiter.

Nun liegen mir aber noch drei Fragen auf der Zunge:
  1. Funktioniert das nun automatisch mit den Access und Refresh Keys und wie kann ich das testen? Ich habe dazu ja wirklich nichts weiteres konfiguriert und frage mich wann genau der die neuen Keys abholt, ohne dass der User sich jedes Mal neu anmelden muss
  2. Meine Nuxt Applikation ist ja public. Sprich gebe ich damit auch die Client Id und das Client Secret heraus. Bedeutet das, ich muss auch einen public Client in Laravel Passport anlegen wie hier beschrieben? Gilt selbes auch für die Flutter App?
  3. Mit Cors muss ich nun nichts mehr beachten oder irgendwie einrichten?
 
Laut dieser Feature-Tabelle sollte es die Tokens refreshen können. Schau mal, ob SessionData die Tokens enthält.

CORS sollte immer verwendet werden. Auf CSRF-Tokens kann verzichtet werden, wenn der Request nicht (auch) durch Cookies authentifiziert werden könnte, sondern immer ein Authorization-Header erforderlich ist.
Ergänzung ()

Bezüglich 2.: keine Ahnung, wie das konkret implementiert ist. Ich könnte mir vorstellen, das useAuth().getSession() ggf. ein aktuelles Token vom Nuxt-Server holt, also das Client-Secret Browser-seitig nicht erforderlich ist. Aber vielleicht kann man das auch einfach als Public Client konfigurieren, die Dokumentation ist da leider etwas dürftig.
 
Zuletzt bearbeitet:
Wie konfiguriere ich die CORS und brauche ich die auch in meiner Flutter App?
 
Ich habe nun alles erfolgreich konfigurieren können, aber bekomme den Login leider nicht hin. Wenn ich mit Postman mich versuche einzuloggen, funktioniert alles. Hier meine Login function:

Code:
public function login(LoginRequest $request): JsonResponse
{
$user = $request->perform();

return $this->successWithPayload([
'user' => new PrivateUserResource($user),
'token' => $user->createToken('access_token')->accessToken,
], __('api.auth.login'));
}

Wenn ich das nun aber mit Nuxt probiere, bin ich ein einem ganz komischen Workflow. Ich habe dieser Anleitung hier gefolgt. Wenn ich dann aber auf den Button Username and Password klicke, wird mir im nachfolgenden Screen ein Button angezeigt mit dem Text "Sign in with Passport" und anschließend, wenn ich diesen geklickt habe, folgende JSON Response

Code:
{"error":"invalid_client","error_description":"Client authentication failed","message":"Client authentication failed"}

1. Wieso kommt im zweiten Schritt nochmal ein Button? Wie kann ich das ändern und direkt die Form an die API schicken?
2. Wieso ist der Client invalid? Habe client id und client secret in der .env Datei hinterlegt. Redirect URL ist, wie in der Doku steht http://localhost:3000/api/auth/callback/laravelpassport
 
Zurück
Oben