I can't find any resource to help with this issue, there are some repos that provide some type of base, but not many of them actually work.
Goals: Run Laravel has the backend API, run NuxtJS as the frontend SPA, either 2 separate locations or combined into one.
Needs to have proper authentication between both systems for logging in users. Laravel Sanctum looks to solve some of the SPA issues, but its hard to find proper documentation that actually shows a fully setup example.
Tested this idea https://github.com/zondycz/laravel-nuxt-sanctum But has failed, doesnt work with npm, must use yarn, however, login errors, doesnt work out of box. Repo needs work.
This tutorial Secure authentication in Nuxt SPA with Laravel as back-end was very indepth, and looked promising, however, refresh tokens don't seem to work with the SPA side since the author developed it on static nuxt. Though I feel like it could be modified to work, I havent found the solution yet.
This template, Laranuxt looked very promising, though I've yet to try it, im not sure if they are regularly updating it at this point, which was previously built by Laravel Nuxt JS (abandoned project)
I was able to run the #2, while refresh tokens dont exactly work, I can still authenticate the user, but now the other issue is password resets, which I'm unable to properly setup through the nuxt form.
Has anyone found resources or solved this issue with communication between these frameworks? or am I going done a rabbit hole that seems to have no end in sight?
I guess another way could be saying, can you do a fully restful authentication system?
Hopefully this isn't too broad of a topic, looking for some guidance on this issue as its hard to find proper tutorials or documentation without writing too much core code myself.
It seems many people struggle to implement Sanctum for SPA authentication when splitting the front and back across separate domains, and the problem is usually CORS related. The Sanctum documentation is great, but assumes a knowledge of CORS (or assumes requests will be same-origin). I'll break down the setup as I see it, providing a little extra support where I feel the docs fall short. A long answer, but towards the end I will address your question which seems to focus specifically on authentication.
Taken from Sanctum documentation:
First, you should configure which domains your SPA will be making requests from.
Assuming your front-end app lives at https://www.my-awesome-app.io, what is the domain? What about http://localhost:3000? Domains map to IP addresses, not protocols or port numbers. So the domains in the given examples would be www.my-awesome-app.io and localhost. With that in mind, all you need to do at this stage is go to the sanctum.php file in your config directory and set the value of the 'stateful' key to match the domain your Laravel API will receive requests from. Although domain names by definition do not include port numbers, the Sanctum docs make it very clear this is also required if you're accessing via a URL that requires a specific port.
/config/sanctum.php
...
'stateful' => [
'localhost:3000',
],
or
'stateful' => [
'my-awesome-app.io',
],
.env files are useful here.
If you are having trouble authenticating with your application from an SPA that executes on a separate subdomain, you have likely misconfigured your CORS (Cross-Origin Resource Sharing) or session cookie settings.
Indeed. So what does a correct setup look like? Assuming a recent Laravel version using the fruitcake/laravel-cors package, you will have a cors.php file in your /config folder. The default looks like:
Default
/config/cors.php
...
'paths' => ['api/*'],
'allowed_methods' => ['*'],
'allowed_origins' => ['*'],
'allowed_origins_patterns' => [],
'allowed_headers' => ['*'],
'exposed_headers' => [],
'max_age' => 0,
'supports_credentials' => false,
We have some work to do here. First, the paths. At the moment, our Laravel API is set up to allow requests from any external origin only if they are trying to access the /api/ routes*. This can lead to trouble early on when, as the Sanctum docs require, we try to access a csrf cookie from the path /sanctum/csrf-cookie. Requests to this path are not explicitly permitted in our cors.php file, so they will fail. To fix, we could do this:
'paths' => [
'api/*',
'sanctum/csrf-cookie'
]
and now requests to /sanctum/csrf-cookie will be permitted. As a sidenote, I find it personally very useful to change the prefix from sanctum to api, that way I can set a single base url for my http client (usually axios).
import axios from 'axios';
axios.defaults.withCredentials = true;
axios.defaults.baseURL = 'http://localhost:3000/api';
To change the path, you can change the following in the /config/sanctum.php file:
'prefix' => 'api',
Now GET requests to /api/csrf-cookie will return the cookie, instead of /sanctum/csrf-cookie.
Next, the allowed-origins. By default, it is set to *, which means "any origin". An origin is the protocol, domain and port number of the app sending a request to your Laravel API. So going back to our earlier examples, their origins would be http://localhost:3000 and https://www.my-awesome-app.io. These are the exact values you should use to allow requests from your front-end app:
'allowed_origins' => ['http://localhost:3000'],
I would recommend moving this to the .env file, and having a separate origin for local and production.
/config/cors.php
...
'allowed_origins' => [env('ALLOWED_ORIGINS')],
/.env
...
ALLOWED_ORIGINS=http://localhost:3000
The documentation does mention the last part of our cors config, which is that
'supports_credentials' => false,
Must be changed to:
'supports_credentials' => true,
Our /config/cors.php file now looks like:
Modified
/config/cors.php
...
'paths' => [
'api/*',
'sanctum/csrf-cookie'
],
'allowed_methods' => ['*'],
'allowed_origins' => [env('ALLOWED_ORIGINS')],
'allowed_origins_patterns' => [],
'allowed_headers' => ['*'],
'exposed_headers' => [],
'max_age' => 0,
'supports_credentials' => true,
Bonus info, Chrome will not allow a credentialed request to a server that returns the header
Access-Control-Allow-Origin: *
Google Chrome: A wildcard '*' cannot be used in the 'Access-Control-Allow-Origin' header when the credentials flag is true
So you should make sure you set a specific origin in your cors config!
Finally, you should ensure your application's session cookie domain configuration supports any subdomain of your root domain. You may do this by prefixing the domain with a leading . within your session configuration file:
This isn't complicated, but seems it can catch people out so thought I'd mention it. Given our examples so far, we'd make the following change to our config/session.php file:
'domain' => '.my-awesome-app.io',
Locally, localhost alone is fine:
'domain' => 'localhost',
Assuming you've followed the rest of the instructions in the Sanctum documentation (setting axios.defaults.withCredentials = true;, adding the middleware etc) your backend configuration is now complete.
Front end and authentication.
I love Sanctum and I'm very grateful for the creators; so I say this with respect; the documentation lacks a little depth at this point. Grabbing the csrf-token is very straight forward, and then...
Once CSRF protection has been initialized, you should make a POST request to the typical Laravel /login route. This /login route may be provided by the laravel/jetstream authentication scaffolding package.
If the login request is successful, you will be authenticated and subsequent requests to your API routes will automatically be authenticated via the session cookie that the Laravel backend issued to your client.
It seems they've updated the docs!
As I write this, I've checked the latest docs and it's now highlighted the fact that you are free to write your own login endpoint. This was always the case, but might have escaped a few people, perhaps given the instructions above ("you should make a POST request to the typical Laravel /login route.") It's also perhaps not clear that you can override default Laravel methods to prevent unwanted side-effects of the default auth setup, like redirecting to the /home page etc.
Writing your own login controller is simple, and I prefer to do so for Sanctum. Here's one you can use:
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Validation\ValidationException;
class LoginController extends Controller
{
public function login(Request $request)
{
$request->validate([
'email' => ['required', 'email'],
'password' => 'required'
]);
$credentials = $request->only('email', 'password');
if (Auth::attempt($credentials)) {
return response()->json(Auth::user(), 200);
}
throw ValidationException::withMessages([
'email' => 'The provided credentails are incorect.'
]);
}
}
Feel free to modify this to suit your needs.
How you manage your state (making sure your app remembers you are logged in, for example) on the front-end is also up to you. There are lots of options, however if we're using Sanctum I think we should focus on a simple cookie-based approach. Here's one I use:
Login to your app. An auth session is established and your browser saves the cookies provided by your Laravel API.
Have your login script return the authenticated user (the one provided above does just that). Save the details of that user to your app state (eg. Vuex).
Check your state contains the user any time you need to secure an action against unauthorised users. Redirect to the login page is the auth check fails.
Here's the above in Nuxt.js form using middleware.
/middleware/auth-check.js
export default async function ({ store, redirect }) {
// Check if the user is not already in the store.
if (store.state.user === null) {
// Call your Laravel API to get the currently authenticated user.
// It doesn't matter if the store has been wiped out due to a page
// refresh- the browser still has the cookies, which will be sent
// along with this request.
try {
let rsp = await user.getAuthenticatedUser()
// If we get the user from the Laravel API, push it back in to
// the store and carry on to the page.
store.commit('SET_AUTH_USER', rsp.data)
} catch (e) {
// If our API doesn't return the user for any reason, redirect to
// the login page.
return redirect('/login')
}
}
// If not, carry on to the page.
}
/pages/admin.vue
export default {
middleware: auth-check
}
The code above is for example purposes, but it's generally what I use for Vue/Nuxt and Sanctum.
Hope this helps, happy to elaborate further if anyone can benefit.
I have multiple front end apps using one database. I wanted to use a single user table to authenticate users for all apps. The problem is some apps access tables in the database through regular authentication while some are isolated reacts apps accessing the database through API authentication.
My question is, can I use the same user table to authenticate users from different apps using both regular and API authentication. For your info, I am using Laravel as a backend. Thank you for your help :).
I guess with regular authentication you mean session and the answer is yes.
Because authentication data and logic are always separated from the authenticatable table (when using jwt you get another table for tokens and with session authentication you use cache or database).
so yes you will use as many guards as you wish with the same table it will look like this in your config/auth.php file:
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
'api' => [
'driver' => 'jwt',
'provider' => 'users',
],
],
I am trying to login with google using socialite , my facebook login works fine so the problem in my google app, any help!!!
'google' => [
'client_id' => 'app-key',
'client_secret' => 'app-secret',
'redirect' => 'http://www.shoptizer.com/callback/google',
],
Also one more point to remember that Socialite also gives uri_mismatch_error even when your redirects are correctly defined in google console but you dynamically changed the redirectUrl through
return Socialite::with('google')->redirectUrl($redirect_url)->redirect();
So plz take care that you should also need to define while receiving the response
Socialite::driver('google')->redirectUrl($redirect_url)->stateless()->user();
where $redirect_url is your custom redirect url.
After google redirects you to correct place, but even then Socialite checks it at its end.
I found this link https://blog.damirmiladinov.com/laravel/laravel-5.2-socialite-google-login.html
From this tutorial:
Occasionally it happens that google require some time to apply client configuration If you get an error message redirect_uri_missmatch wait couple of minutes and it should work normally.
Also change the redirect uri by:
'google' => [
'client_id' => 'app-key',
'client_secret' => 'app-secret',
'redirect' => 'https://www.shoptizer.com/callback/google',
],
If your app is provided by https you must match your http scheme on google api and on your redirect callback.
The problem is in the default url, you must change it on two occasions: before the redirect and before getting the user data.
Do not do this:
return Socialite::driver('google')->redirectUrl($yourredirecturl)->redirect();
Do it:
config()->set('services.google.redirect', $yourredirecturl);
return Socialite::driver('google')->redirect();
And when accessing user data, do this:
config()->set('services.google.redirect', $yourredirecturl);
$user = Socialite::driver('google')->user();
I am doing a project in which I have implemented private chat in Laravel. But for the third party, we use OAuth but i have already used auth() in my project. Can I use both? OAuth is getting token, then communicate with Vue.js. So, I don't want to remove auth() functions in my project. Can you please guide me what to do?
Real time chat system in laravel project. I'm using separate Vue.js with Laravel.
Yes. You can use both OAuth and default Laravel Auth at the same time. In default, Laravel provides routes as web.php and api.php.
web.php: This route uses default Laravel Auth functionality
api.php: Routes defined here uses OAuth functionality
Make sure you use default driver as web in config/auth.php
'defaults' => [
'guard' => 'web',
'passwords' => 'users',
],
I use the default auth/registration in Laravel 5.3.
When I try to register new user I get error:
FatalThrowableError in RegistersUsers.php line 33:
Call to undefined method Illuminate\Auth\TokenGuard::login()
I have made some changes in configuration Laravel:
'defaults' => [
'guard' => 'api',
'passwords' => 'users',
],
So, by default I use api guard
The authentication driver api you are trying to use is TokenBased. That means the server will issue your client a Token on successful authentication using credentials. Then, client can present this token to server while making the request to identify itself.
As given in laravel git, there isn't any method as login().
To use the TokenBased Authentication, here's the good guide