Laravel 9 SPA athentication with nuxt, is saving tokens and sessions in cookies safe? - laravel

So I am making a web app with nuxt 3 and laravel, and I cant seem to get the SPA authentication to work. So I am for now generating a usertoken and saving it in the cookies, so my user keeps logged in. But I am doubting that this is a safe way to keep my user authenticated and do other actions. I tried looking up whether it is good to store it in cookies. But there are to many mixed reviews on this subject.
(the reason why I personally storing it in the cookies, is because nuxt3 is ssr and I wont be able to get the token if it was stored in the localstorage)
I know that cookies are more venerable to xsrf attacks and localstorage to xss attacks.
But what I understand when I am going to use the SPA authentication of laravel, those sessions and tokens are going to be saved in the cookies as well right? So what difference does that make with saving a token in the cookies?

TLDR: store it in the cookies + add some flags to it.
Here is my other answer, HTTPOnly and with Secure adds a layer of security to it.
And that one should probably be totally fine.
XSRF is something that should not happen on your website but if somebody got caught by phishing, you can't really protect the website more than that.
The security realm is a big thing, a system will never be bullet-proof: it's more of a matter of following the best practices as much as possible.
You can mitigate the damages but assigning a short TTL to your tokens and checking their viability on a middleware that runs on every client-side navigation.
I'm not an expert in security but you will probably not need one either. Follow that advice and consider your job done.
Social engineering + other breaches can lead to your website being breached in far easier ways.
If you are a big corporate company that needs those drastic security measures, you also have probably spent millions on ways to lock your network security up.

If your Laravel api(assuming you are using Laravel as API) and SPA(Nuxt) are on the same domain, You can use Sanctum cookie-based session authentication.
#1. Uncomment EnsureFrontendRequestsAreStateful middleware in app/Http/Kernel.php
'api' => [
\Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class,
'throttle:api',
\Illuminate\Routing\Middleware\SubstituteBindings::class,
],
#2. Add SANCTUM_STATEFUL_DOMAINS in your .env file
SANCTUM_STATEFUL_DOMAINS=localhost:3000
#3. In config/cors.php, change support credentials to true
'supports_credentials' => true,
#4. Before you hit login endpoint make request to 'sanctum/csrf-cookie' and then POST request to login endpoint
// Sanctum endpoint to generate cookie
Route::get('sanctum/csrf-cookie', function () {
return response('OK', 204);
});
Route::controller(AuthController::class)->group(function () {
Route::post('auth/login', 'login');
});
#5. Enable the 'withCredentials' option on your application's global axios instance
axios.defaults.withCredentials = true;

Related

Laravel 8 : Is there any good to use the EncryptCookies middleware if the website is HTTPS?

Laravel 8 has an \App\Http\Middleware\EncryptCookies::class middleware that I am wondering whether it is needed in my case.
httpd port setting is done to ensure only HTTPS is allowed for my site.
Based on this question, Does SSL also encrypt cookies?, it seems HTTPS already encrypts everything including cookies.
Therefore my assumption is that there should be no need to enable EncryptCookies middleware in Laravel 8.
I am just not really sure about are the above assumptions I am making correct or not?
Yes, there are benefits to encrypting cookies. Maybe you have some data, e.g. some personal info, user id... that you wish to keep private. Even if you only have session id in the cookie you want that to be private.
Cookies can be read manually in a browser or by some javascript. That data can be used to hack sessions or just to get data that is not supposed to be seen by users.
I never encounter any problems in development or production caused by EncryptCookies middleware or even encrypted cookie itself.
If you use free and default Laravel middleware "EncryptCookies", you are ensuring that data from the cookie, including session id, is kept secure and private.

Is it safe to share authentication state via reactive global store in Vue 3?

I'm building a CMS with vue 3 and want to know if using global store store.store.auth = false/true is a secure way of rendering in/out components that are supposed to be seen only by authenticated users. It goes like this:
User enters credentials in login form
Credentials are sent via HTTP request to backend and checked by laravel sanctum
Response arrives in frontend which sets store.store.auth = true
Components and routes that are supposed to be seen only by authenticated users are rendered via v-if
Is this a secure approach or can it be improved?
The security, in this case, depends almost entirely the backend.
Sanctum does not use tokens of any kind. Instead, Sanctum uses Laravel's built-in cookie based session authentication services. Typically, Sanctum utilizes Laravel's web authentication guard to accomplish this. This provides the benefits of CSRF protection, session authentication, as well as protects against leakage of the authentication credentials via XSS.
src
It seems like sanctum handles the authentication, so you should be fine as long as
store.store.auth value is kept up to date, and
the API does it's own authentication and authorization.
Because the entirety of the application is visible through the js source someone could potentially modify state and display options that they shouldn't see. This would be really-really difficult to prevent in SPA, that's why it is paramount that the backend handles this correctly.
You may be able to use code splitting, to prevent loading parts of the application that require authentication, but this is not security measure.

Laravel SPA (Vue) Authentication with cookie or token?

the more I read about Laravel Spa (Vue) authentication, the more I ask myself about the "best way" to authenticate with Sanctum.
Official Laravel documentation says:
For this feature, Sanctum does not use tokens of any kind. Instead,
Sanctum uses Laravel's built-in cookie based session authentication
services. This approach to authentication provides the benefits of
CSRF protection, session authentication, as well as protects against
leakage of the authentication credentials via XSS.
But a lot of videos on YouTube or other tutorials on the internet all using (bearer) tokens which sounds contradictory to me. I mean, just using a single token for authentication seems to be a bit unsafe to me.
Also, some of those people defined "login" and "register" routes directly into Laravels route file, instead of using Vue router.
I'm using Laravel 8, VueJS 3 and Vuex 4.
So, what do you think: Am I on the right way by using Vue routes and sanctum authentication using cookies or not? And why?
Thank you, I appreciate that.

Laravel Passport APi - Implicit grant

I want to build a spa via angularjs and use laravel as a api for the spa. Reading trough the docs of laravel passport i discovered that i need to use the implicit grant for this purpose. But i am not really sure in how it should work from front to back. I just want to have the ability to log in a user with a username and password and then just use it and i need some clarification on the process. This is what i want:
Log in with a user by a username and password via html/javascript to laravel (Angular) via an ajax request.
Get an access token to communicate with the api
Do some action in the spa that triggers a request to the api using the access token
Getting data back from the api in response to that request.
But what i see now with the implicit grant i a bit different than what i expect.
Log in to laravel via a default blade login form (did not create one using ajax yet)
Redirect to oauth/autorize like this
Route::get('/redirect', function () {
$query = http_build_query([
'client_id' => 'client-id',
'response_type' => 'token',
'scope' => '',
]);
return redirect('http://your-app.com/oauth/authorize?'.$query);
});
The redirect shows an approve or deny authorization request screen (this is not what i expect)
When i approve the request, the browser redirects me to the redirect uri that is specified in the oAuth client database entry with the access token. And i should be able to.
What confuses me even more is the fact that i seem to need a new client for each laravel user. I expect to have 1 oauth client representing my spa that can access the laravel users. Could you please clarify this?
If you are going to use a password grant in a JavaScript application then you must use a server side proxy to do the authentication and secure both client_secret and the refresh token.
The proxy manages the whole api communication process or just the authentication part and returns a short lived access_token . Authentication state is managed via a server session. Some requests must be protected from CSRF exploits depending on your implementation since most implementations use a cookie.
Otherwise use an implicit grant to authenticate your app. (See links below for more info)
https://auth0.com/docs/api-auth/tutorials/implicit-grant
https://oauth2.thephpleague.com/authorization-server/implicit-grant/
You can refresh your access token using silent authentication as described here
https://auth0.com/docs/api-auth/tutorials/silent-authentication
NB: In most cases refresh tokens do not expire, that's a big NO for Frontend storage.
Client Secret should always be kept secret.
Edit (2020)
It's now 2020 and a lot has changed in the web security world.
There are known vulnerabilities with implicit grant especially since your access_token can be intercepted mid-flight and redirected to another server.
It's now recommended to use PKCE flow instead of implicit grant
Okta has a very nice article and video regarding this Is the OAuth 2.0 Implicit Flow Dead?
Laravel has also released a much simpler alternative Laravel Sanctum I suggest you have a look at it as it uses secure HTTP only cookies for access token storage and also implements CSRF protection out of the box

Authorize PHP application permanently to make requests to JWT auth protected API

Maybe I searched with the wrong keywords but I never found anything about the following scenario:
I have both an API with JWT auth (Laravel + tymon/jwt-auth) and a PHP application that should query that API protected by a JWT token.
How can I make sure that the app always is authentificated? After reading a lot of tutorials and article about JWT auth I'm left with this ideas:
using a never expiring token which is stored permanently in the consuming application. If I understand it right this could be a security concern because someone who has access to that token has access to the api as long as he want? But I don't understand why this token shouldn't be invalidated if the token has been stolen?
refresh the token on every request and invalidate the old one. This implies that the consuming application have to update the token after each request in it's storage (database would make the most sense, I guess). In my opinion this produces a lot of overhead and it doesn't prevent for jwt-auth's refresh_ttl setting.
using an additional API request (perhabs cron based?) to a refresh route to prevent the token from expiring. Again there is the jwt-auth's refresh_ttl problem I think.
I wonder why there seems to be no discussions/articles about that scenario.
Any help on that subject I would very much welcome!
You don't want your user logging in every time but you also don't want them to be logged forever.
Here are my thoughts
I have worked with 1 year tokens for comercial applications, I was using it for low level third party developers, the api concept was already overwhelming for them so I went easy on the auth thingy. Once every year their application broke and they had to reach out to get the new token, bad design but it worked.
Refreshing your token on every request will kill your performance and let attackers have a consistent way to break/predict your key, no good.
In my opinion, this is your most elegant suggestion. You could use some PWA features to accomplish that.
I would suggest increasing the refresh_ttl to 30 days and keep the ttl on one hour.
If you're using SPA or heavy js apps:
On your javascript you could do an ajax setup (or prototype or whatever your javascript framework uses for oop) and have a call to refresh whenever you get a .
If you're using just common page refresh for your apps, store you JWT on a cookie, then your application can refresh it whenever it needs and there will be no special js to make. HTTPS will take care of security.

Resources