Nuxt.js / Sanctum : $auth.user still empty - laravel

Little question: my authentication with Sanctum has issues...
My login fonction:
const response = await axios.get(`${process.env.apiUrl}/sanctum/csrf-cookie`)
console.log(response)
const res = await this.$auth.loginWith('laravelSanctum', {
data: {
email: this.userLogin.login.email,
password: this.userLogin.login.password,
}
})
console.log(res);
console.log(this.$auth)
this.$router.push('/mon-compte/mon-espace');
In local:
The first consoleLog is ok, API CSRF Cookie is OK.
The second consoleLog is ok too, API Login is OK.
The third consoleLog is ok, $auth.user contain all informations returned by API Login.
3 APIs are called : csrf-cookie / login / user.
I'm connected.
But in Staging (prod dev):
The first consoleLog is ok, API CSRF Cookie is OK.
The second consoleLog is ok too, API Login is OK.
The third consoleLog is not ok, $auth.user is empty.
Only 2 APIs are called: csrf-cookie / login.
I don't understand...
My nuxt.config.js:
auth: {
strategies: {
'laravelSanctum': {
provider: 'laravel/sanctum',
url: process.env.apiUrl,
endpoints:{
login: {
url: '/api/login',
method: 'post',
propertyName: 'access_token'
},
user: {
url: '/api/user',
method: 'get',
propertyName: false
},
logout: {
url: '/api/logout',
method: 'post'
},
},
register: {
url: '/api/register',
method: 'post'
}
}
},
redirect: {
login: '/mon-compte/login',
logout: '/mon-compte/login',
home: '/mon-compte/mon-espace',
register: '/mon-compte/register'
}
},
And on Laravel, api.php:
Route::apiResource('user', UserController::class);
Route::post('/login', [AuthController::class, 'login']);
Route::post('/logout', [AuthController::class, 'logout']);
Route::post('/register', [AuthController::class, 'register']);
Route::post('/me', [AuthController::class, 'me']);
And my authController:
public function register(Request $request)
{
$validateData = $request->validate([
'name' => 'required|string|max:255',
'email' => 'required|string|email|max:255|unique:users',
'password' => 'required|string|min:8'
]);
$user = User::create([
'email' => $validateData['email'],
'name' => $validateData['name'],
'type' => 'user',
'password' => bcrypt($validateData['password'])
]);
$token = $user->createToken('auth_token')->plainTextToken;
return response()->json([
'access_token' => $token,
'token_type' => 'Bearer'
]);
}
public function login(Request $request)
{
if (!Auth::attempt($request->only('email', 'password'))) {
return response()->json([
'message' => 'Login information is invalid.'
], 401);
}
$user = User::where('email', $request['email'])->firstOrFail();
$token = $user->createToken('authToken')->plainTextToken;
return response()->json([
'access_token' => $token,
'token_type' => 'Bearer',
'user' => $user
]);
}
public function me(Request $request)
{
return response()->json(['data' => $request->user(), "result" => true]);
}
public function logout(Request $request){
Auth::logout();
auth()->guard('sanctum')->logout();
//auth('sanctum')->logout();
$request->session()->invalidate();
$request->session()->regenerateToken();
return response()->json(['message' => 'Client successfully signed out']);
}
Any ideas?
What i'm doing wrong?
Thanks a lot!

I believe you don't have a user endpoint to fetch the user after login, because nuxt-auth will do an api request to the endpoint you set in your nuxt.config.js which fethes the logged in user.
And for CSRF token you don't need to make the request the nuxt-auth will take care of that.
public function me(Request $request)
{
return response()->json(['data' => $request->user(), "result" => true]);
}

Related

Laravel sanctum and vue: user is logged in frontend but backend returns unauthorized

i have a log in form in my front end (vue) when users log in, in vue i can get back data of logged in user perfectly fine through
axios.get('http://127.0.0.1:8000/api/user').then((response)=>{
this.userData = response.data;
However in my backend when i try to bring back the logged in user though
if ($request->user('sanctum')) {
return "auth";
} else {
return "guest";
}
it returns guest i dont know why!!!!
vue code:
async login(){
axios.post('http://127.0.0.1:8000/api/login', this.form).then((response) =>{
localStorage.setItem('token', response.data);
axios.defaults.headers.common['Authorization'] = `Bearer ${response.data.token}`;
this.$router.push('/');
} )
.catch ((error) =>{
console.log(error.response.data.errors);
})
},
laravel auth controller :
public function loginn(Request $request){
$request->validate([
'email' => 'required',
'password' => 'required',
]);
$user = User::where('email', $request->email)->first();
if (! $user || ! Hash::check($request->password, $user->password)) {
throw ValidationException::withMessages([
'email' => ['The provided credentials are incorrect.'],
]);
}
return $user->createToken("token")->plainTextToken;
return response()->json([
'token' => $token,
'type' => 'bearer',
'expires_in' => auth()->factory()->getTTL() * 60
]);
api.php
Route::middleware('auth:sanctum')->get('/user', function (Request $request) {
return $request->user();
});
Route::post('/signup', [authcontroller::class, 'signupp']);
Route::post('/login', [authcontroller::class, 'loginn'])->name('login');;
Route::post('/logout',[authcontroller::class, 'logout'])->middleware('auth:sanctum');
I haved this problem.
This problem is for .env in backend laravel and get csrf front
remembering that the localhost address must be either localhost or 127.0.0.1 amd get csrf before
axios.get('/sanctum/csrf-cookie').then(response => {
// Login...
});
.env
SESSION_DOMAIN=127.0.0.1
SACTUM_STATEFUL_DOMAINS=127.0.01:PORT

how to retrieve user info using laravel auth sanctum API

I'm currently developing a mobile apps for my web based system. I'm using laravel as my API .
Currently, I want to do where when User A login, it will only shown User A info.
How can I achieve that ?
This is my AuthController where it generate my tokens.
public function login(Request $request)
{
try {
$validateUser = Validator::make($request->all(),
[
'username' => 'required',
'password' => 'required'
]);
if($validateUser->fails()){
return response()->json([
'status' => false,
'message' => 'validation error',
'errors' => $validateUser->errors()
], 401);
}
$user = UserRegister::where('username', $request->username)->first();
if(!$user || !Hash::check($request['password'], $user->password)) {
return response([
'message' => 'Username & Password does not match'
], 401);
}
return response()->json([
'status' => true,
'message' => 'User Logged In Successfully',
'user' => $user,
'token' => $user->createToken("remember_token")->plainTextToken
], 200);
} catch (\Throwable $th) {
return response()->json([
'status' => false,
'message' => $th->getMessage()
], 500);
}
}
This is my api routes
Route::post('/login', [AuthController::class, 'login']);
// Homepage routes
Route::group(['middleware' => ['auth:sanctum']], function () {
Route::post('/logout', [AuthController::class, 'logout']);
Route::get('/technician', [HomepageController::class, 'technician']);
});
Route::middleware('auth:api')->get('/user', function (Request $request) {
return $request->user();
});
and this is my HomepageController where I tried to retrieve user A data only but it does not work.
public function technician()
{
$technician=JobRegister::where('job_assign', auth()->user()->name);
return response()->json($technician);
}
This is my query for web based system.
$query = "SELECT * FROM job_register WHERE job_assign ='{$_SESSION['username']}'"
i want to make user A can only look at their job details that been assign.
do you have any idea how to do it ? your help is much appreciated. thank you.
try this
$username=Auth()->user()->userName //this will return you username of logged in user
$query = "SELECT * FROM job_register WHERE job_assign ='$username'"
don't forget to use auth namespace top of in your controller like this
use Auth;

Laravel sanctum with react same domain 401 authentication error using cookies

Authenticating with the sanctum token is working just fine but sadly I can't get it to work using cookies instead (calling /api/user returns 401 Unauthorized). I'd really like to make use of the cookie authentication because it's safer.
Does anyone has an idea of what I'm doing wrong (or missing) to make the authentication work based on cookie so the frontend doesn't have to send sanctums bearer token?
Setup
I'm running React outside of Laravel but both the laravel backend and the react frontend are running on the same domain under subdomains (api.website.com and customer.website.com).
.env
SESSION_DRIVER=cookie
SESSION_DOMAIN=.website.com
SESSION_LIFETIME=120
SESSION_SECURE_COOKIE=false
SANCTUM_STATEFUL_DOMAINS=localhost:8000,.website.com
kernel.php
'api' => [
\Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class,
'throttle:api',
\Illuminate\Routing\Middleware\SubstituteBindings::class,
],
session.php
'same_site' => 'lax',
'http_only' => true,
'driver' => env('SESSION_DRIVER', 'file'),
'cookie' => env(
'SESSION_COOKIE',
Str::slug(env('APP_NAME', 'laravel'), '_').'_session'
),
cors.php
'paths' => ['api/*', 'sanctum/csrf-cookie'],
'allowed_methods' => ['*'],
'allowed_origins' => ['http://localhost:3000', 'https://api.website.com', 'https://customer.website.com'],
'allowed_origins_patterns' => [],
'allowed_headers' => ['x-csrf-token', 'x-xsrf-token', 'content-type'],
'exposed_headers' => [],
'max_age' => 0,
'supports_credentials' => true,
UserController.php
public function login(Request $request)
{
if (!$request->email) {
return response()->json(['error' => 'Missing email'], 401);
} elseif (!$request->password) {
return response()->json(['error' => 'Missing password'], 401);
} elseif (!$request->device_name) {
return response()->json(['error' => 'Missing device_name'], 401);
} else {
$credentials = $request->validate([
'email' => ['required', 'email'],
'password' => ['required'],
]);
if (Auth::attempt($credentials)) {
$auth = Auth::user();
$token = $auth->createToken($request->device_name)->plainTextToken;
$auth->setAttribute('token', $token);
return response()->json($token, 200);
}
return response()->json(['error' => 'The provided credentials do not match our records.'], 401);
}
}
Api.php
// Force all API responses to be in JSON format.
Route::middleware('json.response')->group(function () {
// UNAUTHENTICATED API's.
Route::post('login', [UserController::class, 'login']);
// AUTHENTICATED API's.
Route::middleware('auth:sanctum')->group(function () {
// USER.
Route::get('/user', function (Request $request) {
return $request->user();
});
// ADMIN.
Route::middleware('role.admin')->group(function () {
Route::get('/migrate', function () {
artisan::call('migrate');
return response()->json("success", 200);
});
Route::get('/route/clear', function () {
artisan::call('route:clear');
return response()->json("success", 200);
});
});
});
});
Frontend
const instance = axios.create({
withCredentials: true,
headers: {
Accept: 'application/json',
},
});
const loginWithEmailPasswordAsync = async (email, password) => {
// eslint-disable-next-line no-return-await
return await instance
.post('https://api.website.com/api/login', {
email,
password,
device_name: '_device',
})
.then((res) => {
return instance
.get('https://api.website.com/api/user')
.then((user) => {
return user;
})
.catch((error) => error);
})
.catch((error) => error);
};
try {
instance
.get('https://api.website.com/sanctum/csrf-cookie')
.catch((error) => error);
const loginUser = yield call(loginWithEmailPasswordAsync, email, password);....
Request and response headers when the 401 Unauthorized error pops up
Not sure if it matters but in my browser network tab I do see what seems to be the correct request headers such as the filled in X-XSRF-TOKEN, Cookie and in the response headers the set-cookie = laravel_session=ySiTVYYvyFKHSt9Q0VnP2vl4xeIee0MnjvlfQSu4; expires=Tue, 02-Aug-2022 18:55:13 GMT; Max-Age=7200; path=/; domain=.website.com; httponly; samesite=lax
I think you need to change SANCTUM_STATEFUL_DOMAINS from this
SANCTUM_STATEFUL_DOMAINS=localhost:8000,.website.com
to this:
SANCTUM_STATEFUL_DOMAINS=localhost:8000,customer.website.com
Since you'll have different .env for your dev and production environment, I think you should remove localhost host totally.
You can change your code from
SANCTUM_STATEFUL_DOMAINS=localhost:8000,.website.com
To
SANCTUM_STATEFUL_DOMAINS=website.com,frontend-subdomain-if-any.website.com

Nuxt-Laravel-Sanctum CSRF token mismatch 419 error

I have a Nuxt-Laravel-Sanctum CSRF token mismatch 419 error while Laravel is hosted on a server and Nuxt is on localhost on a PC. I have uploaded my Laravel project for getting API on api.repairtofix.com.
And I am trying to log in from localhost in my pc from Nuxt. While clicking on the login button I get the following error.
{message: "CSRF token mismatch.", exception:
"Symfony\Component\HttpKernel\Exception\HttpException",…}
Login method
login() {
this.$auth.loginWith('laravelSanctum', {
data: this.form
})
.then(response => console.log(response))
.catch(error => console.log(response))
}
.env
APP_URL=http://api.repairtofix.com
SESSION_DOMAIN=api.repairtofix.com
SANCTUM_STATEFUL_DOMAINS=.repairtofix.com,localhost:3000
Kernel.php
'api' => [
EnsureFrontendRequestsAreStateful::class,
'throttle:api',
\Illuminate\Routing\Middleware\SubstituteBindings::class,
],
sanctum.php
'stateful' => explode(',', env('SANCTUM_STATEFUL_DOMAINS',
'api.repairtofix.com,localhost,localhost:3000,127.0.0.1,127.0.0.1:8000,::1'
)),
cors.php
'paths' => ['api/*', 'sanctum/csrf-cookie', 'login', 'signup', 'getUser'],
'allowed_methods' => ['*'],
'allowed_origins' => ['*'],
'allowed_origins_patterns' => [],
'allowed_headers' => ['*'],
'exposed_headers' => [],
'max_age' => 0,
'supports_credentials' => true,
api.php
Route::middleware('auth:sanctum')->get('/user', function (Request $request) {
return $request->user();
});
// register
Route::get('register', function(Request $request){
$user = User::create([
'name' => $request->name,
'email' => $request->email,
'password' => bcrypt($request->password)
]);
return $user;
});
// login
Route::post('login', function(Request $request){
$credentials = $request->only('email', 'password');
if(!auth()->attempt($credentials)){
throw ValidationException::withMessages([
'email' => 'Invalid credentials'
]);
}
$request->session()->regenerate();
return response()->json(null, 201);
});
// logout
Route::post('logout', function(Request $request){
auth()->guard('web')->logout();
$request->session()->invalidate();
$request->session()->regenerateToken();
return response()->json(null, 201);
});
nuxt.config.js
modules: [
'#nuxtjs/axios',
'#nuxtjs/pwa',
'#nuxtjs/auth-next',
'#nuxtjs/toast',
],
auth:{
strategies: {
'laravelSanctum': {
provider: 'laravel/sanctum',
url: 'http://api.repairtofix.com',
endpoints: {
login: {
url: '/api/login'
},
logout: {
url: '/api/logout'
},
user: {
url: '/api/user'
},
},
user: {
property: false
}
},
},
redirect: {
login: "/login",
logout: "/",
home: "/"
}
},
I guess you are using SPA authentication with sanctum, both your server and client has to be on the same domain. The client(localhost) and your api is on different domain.
docs
In order to authenticate, your SPA and API must share the same top-level domain. However, they may be placed on different subdomains.
In my case, Axios credentials were not set to true in nuxt.config file, also the text is case sensitive
axios: {
baseUrl: 'http://localhost:8000',
credentials: true,
},
It is maybe a little bit late but others in future.
1-check the api/config/sanctum in laravel and make the ports correct on localhost:xxxx and 127.0.0.1:xxxx
2-on .env file make coorection for SANCTUM_STATEFUL_DOMAINS=localhost:xxxx
Add the below statement to your .env file and clear the cache.
AIRLOCK_STATEFUL_DOMAINS=127.0.0.1

error":"token_not_provided: API Authentication in Laravel, Vue and JWT

I am creating JWT API authentication in Laravel with as stated in guide this link:
https://codeburst.io/api-authentication-in-laravel-vue-spa-using-jwt-auth-d8251b3632e0
Everything else is fine but I am having this issue on login:
error":"token_not_provided
Login seem to be going through successfully as I can see in the console or postman, but the token is never being retrieved. This is happening when the app tries to load the user data at api/auth/user end point.
GET http://127.0.0.1:8000/api/auth/user 400 (Bad Request)
this is my login method:
public function login(Request $request)
{
$credentials = $request->only('email', 'password');
if ( ! $token = JWTAuth::attempt($credentials)) {
return response([
'status' => 'error',
'error' => 'invalid.credentials',
'msg' => 'Invalid Credentials.'
], 400);
}
return response([
'status' => 'success'
]) ->header('Authorization', $token);
}
Then the user method
public function user(Request $request)
{
$user = User::find(Auth::User()->id);
return response([
'status' => 'success',
'data' => $user
]);
return $user;
}
Authentication Routes:
Route::post('auth/login', 'JWTAuthenticateController#login');
Route::group(['middleware' => 'jwt.auth'], function(){
Route::post('auth/logout', 'JWTAuthenticateController#APIlogout');
Route::get('auth/user', 'JWTAuthenticateController#user');
});
VueJS Login Component:
<script>
export default {
data(){
return {
email: null,
password: null,
error: false
}
},
methods: {
login(){
var app = this
this.$auth.login({
params: {
email: app.email,
password: app.password,
},
success: function () {
console.log('Success')
},
error: function () {
console.log('Something Went wrong!')
},
rememberMe: true,
redirect: {name:'inventories'},
fetchUser: true,
});
},
}
}
</script>
I cannot figure out how to fix this. Just don't tell why the authorization header not being returned:
return response([
'status' => 'success'
]) ->header('Authorization', $token);
Please Assist.

Resources