Laravel Passport and PKCE authentication - Do you need a session for the user to login? - laravel

I setup a PKCE authentication system for an API using Laravel Passport.
At the moment this API is used by a SPA.
The authentication flow is the following :
User clicks on "login" on the SPA
User is redirected to the API /oauth/authorize endpoint (with all the pkce required parameters)
Now, that API endpoint requires the user to be authenticated. So the login page is shown (its a php Laravel served view)
The user logs in, clicks on authorize, and is redirected to the callback url of the SPA, which will then send a request to obtain the JWT token.
From this point all communication from the SPA and the API will use the JWT token only.
Everything works. Except I now have a few doubts.
Is it correct for the login on step 3 to be session based ? To set that up I simply used Laravel UI, which provides an already setup login functionality, which is session based.
If I visit the API login page again, by its own url, I am actually session logged in (which is normal). Of couse if I logout from that page (it has also a logout button), I can still use the SPA normally, as I still have my JWT token which is used by Passport.
To solve the logout problem I had to implement a 'double' logout, one that clears the JWT from local storage for the SPA, and one to logout the user from the session login of the Laravel api (in case that was still active at the time).
All this seems a little off, should I refactor the login function of Laravel UI to not start a session (if that is even possible) ? Or maybe log the user out in some way(how ?) after the redirect to the SPA callback url ?
Thanks

Related

Add a SSO flow to Laravel Passport

We are trying to implement a SSO solution using Laravel Passport. There is already a question about this topic but I think this one is more about the nitty-gritty.
Our requirements are:
A Laravel Passport service running on passport.com
Some first-party sites on various domains: foo.com, bar.com
Users can log in to foo.com and bar.com by typing their access details directly (Password Grant)
If a user logs in to foo.com and then they visit bar.com they should be automatically logged in
Based on my understanding of Oauth2, the system should work like the following:
Initial login flow:
The user types in their details on foo.com
foo.com makes a request to passport.com/oauth/token using a Password Grant and retrives an Access Token and a Refresh Token. Additionally, a SSO Token is generated and returned.
foo.com redirects the user to passport.com/sso/passthrough , passing the SSO Token and a return URL as query parameters.
passport.com saves the token as a cookie and then redirects to the return URL.
The user returns on foo.com and they can use the site
Note that the redirect to passport.com MUST take place, as otherwise browsers like Safari and Chrome in incognito will consider passport.com to be a third-party domain and the cookie will be blocked.
SSO flow:
The user visits bar.com
bar.com makes an AJAX request to passport.com/oauth/authorize using a SSO Grant and the redirect URI bar.com/sso/return
On passport.com, the SSO Grant looks for the SSO Token in the cookies and if the token is found, an authorization code is produced and sent bar.com/sso/return as a redirect. Because AJAX requests don't handle redirects, control passes directly to bar.com.
bar.com exchanges the authorization code for an access token and returns a successful AJAX response
bar.com receives the AJAX response and triggers a page refresh since the user is now logged in
For clarity, the SSO Token, SSO Grant, passport.com/sso/passthrough and bar.com/sso/return routes are not part of Laravel Passport; they are new concepts that we are implementing here.
The questions here are:
This flow looks to me like it should work. Am I missing anything?
Does this introduce any vulnerability into the Oauth2 flow? The Access Token and Refresh Token are never displayed to the client, but the SSO Token is. If an attacker steals it, I'm guessing they could potentially impersonate the user.
The Oauth2 protocol and Laravel Passport are stateless. By adding a cookie we are adding state. Is this a necessary evil or can it be done in a different way?
Should the SSO Token be saved to the cookie directly or should there be a different kind of token or authorization code there?
Any tips for implementing the SSO Grant and SSO Token?

Laravel Vue JS JWT Implementation

I am trying to understand how an auth in a spa context with a jwt token should be implemented based on a Register / Login / Logout process. I have been searching on the web and have implemented at laravel side tymon jwt but I am confused about next step regarding register form and login form.
Do I understand well that when my user register for the first time on my website, this is at this time that the JWT token should be generated and recorded in a cookie ? If yes, is it Vue or Laravel which should record the JWT token in a cookie ? I suppose Vue ?! If yes, in which manner?
Other question: what happen if the user clear the browser cache and eliminate the cookie containing the JWT form his computer ? Does he need to register again to get a a new token ?? I am totally confused about the process.
Getting a more detailed and step by step process would help.
Thanks
The rough sketch for a JWT authentication works like this:
Registration - (optional | If the user is not registered) User fills the registration form which is posted to the register route, User account is created and the api responds with 201 ( content created)
Login - User uses his credentials to login to the app. The credentials are verified and a JWT token is issued and sent back to the user.
Vue handles the JWT Token and stores the provided token into cookies ( you can use js-cookie to handle this, usually in Vuex state )
The token is used with every request sent forth to the server, server verifies the Token and then the request proceeds.
Logging out requests the server to invalidate the token and then removes the token from the cookies.
You can use laravel passport, Laravel Sanctum or tymon/Jwt for token management.

Best Way To Integrate Server Side Laravel Login VueJS SPA

How can I authenticate a user with sanctum when the whole login process happens server side? The question I am asking is kind of hard to phrase so I will explain my situation.
I have a Vue SPA for my front end and a Laravel app as a backend api (they run on the same domain). Normally, to authenticate with the laravel api using sanctum, you would send the credentials in a post request, and if the login was successful, you would get the session information returned. However, I want to use steam login for authentication. I already have to whole process on the backend figured out in terms of actually logging in, however I am unsure how to pass the session data back to the SPA. Currently I have a link on my site that takes the user to the login endpoint on the api, and that endpoint will have them authenticate with steam, so the entire login process is handled on the backend. Now I just need to figure out how to send the session data back to the SPA. I guess it world be similar to using sanctum with socialite.
So far I've tried usisng Sanctums Mobile Aplication Authentication. I did this by having the user log in into the laravel app using steam, then once authenticated, a access token for their account would be created, and they would get redirected back to the Vue apps call back file, with the token as a part of the query string. Then the token would be stored and . This worked, however it presented some security issues.
The token was passed back in the url, so anyone could screenshot it and use it
Anyone who obtained the token by some other method could use it.
Here is the code for what I tried: https://gist.github.com/DriedSponge/4e8549486c2bfa33e4c0b21a539bdf85
So in summary, I want the entire login process to take place on the server, but somehow at the same time authenticate the SPA. If you have any ideas on how I can make this work, please let me know. If you have any questions just leave a comment. Thanks in advance.

spring oauth2 authorize flow in single page app

I am implementing an oauth2 authorization server for providing access to our apis.
Our application is a single page application, with the a jwt token in the authentication header to provide access.
We want to setup an oauth2 Authorization Code flow like,
User is on external site and wants to get access to our apis
External site redirects to our site/spa with oauth2 params, client_id etc.
SPA checks authentication, users needs to login to continue
User sees page for confirming access
User confirms access, code is returned and redirected to external site
External site does backchannel call to obtain token from code
My problem is in 4 and 5, in standard Spring setup this is provided by
org.springframework.security.oauth2.provider.endpoint.AuthorizationEndpoint,
on /oauth/authorize GET oauth params are stored in the session and the confirmation page is shown, and on post of that the code is returned in the redirect.
But I cannot find any guidance/examples on how to do this with a page hosted in a SPA.
You have to be authenticated in this endpoint and I cannot really use the top level page that /oauth/authorized provides because we use header based authentication on rest api calls only, all our top level calls are unauthenticated.
Is there some obvious way to make this work?
I think I do not want to put my authentication token in a cookie.
I was thinking of just then creating a controller that sort of does what the AuthorizationEndpoint does and returning a redirect to the redirect in Javascript. But I am not sure if I would be breaking some other security requirement.

OAuth2 Implicit flow vs 'Traditional' session based auth for small SPA

Some background:
I am writing a small SPA that will use a back end that I have also written. The JS and the back end API are on the same server.
i.e. SPA will load from foo.com, back end is at foo.com/api
In the past I have always used Spring Security with simple form based login. After logging in the user will get a session cookie. Pretty standard stuff.
For this app I looked into OAuth2 implicit flow. My understanding is the User would load my page, then from the SPA I would direct the user to the authorization endpoint so my app could get a token. The user would be redirected from the authorization endpoint to a login form. After the user authenticated with the form.. they would be redirected back to the authorization endpoint to get the token and possibly grant access to the JS client. After that the user would be redirected to a URL specified by the client, with the new access token as a URL fragment.
I have this working and its all great. The part I don't quite get is this:
When the user is redirected to the login form and they authenticate a session is created on the server that has to at least last long enough for the user to be redirected to the authorization endpoint to get the token. At that point they already have an authenticated session on my server, why not just stop there and use traditional cookie and session based logins?

Resources