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.
Related
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]);
}
I want to get the errors from the server in the client, show them on the page when there's some troubles during login or registration, I think it's ok in the backend, but I don't know why they're not returning.
How to get that error messages from the validator in Vue?
I'm using: vuex, vue-router
My vuex file for login and register
actions: {
async login({ dispatch }, credentials) {
await axios.post('http://127.0.0.1:8000/api/login', credentials)
.then( res => {
if (res.data.success) {
// controllo se il token è buono
return dispatch('attempt', res.data.token)
}
})
.catch( err => {
console.log( err )
})
},
async attempt({ commit, state }, token) {
// blocco in caso ci fosse o meno il token
// se c'è il token
if (token) {
commit('SET_TOKEN', token)
}
// se non c'è
if(!state.token) {
return
}
// /blocco in caso ci fosse o meno il token
// provo a gettare l'user
try {
await axios.get('http://127.0.0.1:8000/api/user')
.then(res => {
commit('SET_USER', res.data)
})
} catch (e) {
commit('SET_TOKEN', null)
commit('SET_USER', null)
}
},
async register({ }, credentials) {
await axios.post('http://127.0.0.1:8000/api/register', credentials)
.then( () => {
})
.catch(err => {
console.log(err)
})
},
logoutAction({ commit }) {
return axios.post('http://127.0.0.1:8000/api/logout')
.then( () => {
commit('SET_TOKEN', null)
commit('SET_USER', null)
})
},
}
My controller
public function register(Request $request) {
$fields = $request->validate(
[
'name' => 'required|string',
'email' => 'required|string|unique:users,email',
'password' => 'required|string|confirmed'
]
);
$user = User::create([
'name' => ucwords($fields['name']),
'email' => $fields['email'],
'password' => bcrypt($fields['password']),
]);
$token = $user->createToken('token')->plainTextToken;
return response()->json(
[
'success' => true,
'user' => $user,
'token' => $token,
'message' => 'Registered successfully'
], 201);
}
public function login(Request $request) {
$fields = $request->all();
$validator = Validator::make($fields, [
'email' => 'required',
'password' => 'required'
]);
$user = User::where('email', $fields['email'])->first();
if($validator->fails()) {
return response()->json([
'message' => 'You must fill in all the fields!',
'errors' => $validator->errors()
], 401);
}
if(!$user || !Hash::check($fields['password'], $user->password)) {
return response()->json([
'message' => 'Invalid credentials.',
], 401);
}
$token = $user->createToken('token')->plainTextToken;
return response()->json(
[
'success' => true,
'user' => $user,
'token' => $token,
'message' => 'Logged in'
], 201);
}
public function logout(Request $request) {
auth()->user()->tokens()->delete();
return response()->json(
[
'message' => 'Logged out.'
]
);
}
Also I want to stop the user if the registration has empty fields, forcing him to stay in the register route, but with these settings down here the user will be redirected to the login page even if no registration fields are been typed in, as soon as I press enter or click 'register'.
p.s.: the 'home' route in which I'm pushing in the user is the page with the login form. So I want that the user will be redirect there only if the register form has been fulfilled.
submitRegistration() {
this.register(this.form)
.then(() => {
this.$router.push({name:'home'})
})
.catch((err) => {
// Ignore the vuex err regarding navigating to the page they are already on.
if (
err.name !== "NavigationDuplicated" &&
!err.message.includes(
"Avoided redundant navigation to current location"
)
) {
// But print any other errors to the console
console.log(err);
}
});
},
I use this class for multiple projects and I never had any problems,
Today impossible to check user after JWT authentication
public function check()
{
return response()->json( Auth::guard()->check());
}
public function login(Request $request)
{
$credentials = $request->only('email', 'password');
if ($token = Auth::guard()->attempt($credentials)) {
return $this->respondWithToken($token);
}
return response()->json(['message' => __('commons.response.error.login')], 401);
}
protected function respondWithToken(string $token)
{
return response()->json([
'check' => Auth::guard()->check(),
'access_token' => $token,
'token_type' => 'bearer',
'auth' => true,
'me' => Auth::guard()->user(),
'message' => __('commons.response.success.login', ['user' => Auth::guard()->user()->name]),
]);
}
The login function returns the user and check return true
After that, check() return false
any idea ?
Thank you
Edit
I find it, it was a front end issue, the request token cannot be found
axios.defaults.headers.common['Authorization'] = `Bearer ` + localStorage.token;
I miss the line
localStorage.setItem('token', r.data.access_token);
Done
I have created an API using Laravel 5.4 and in there I have implemented JWT authentication. Now, I'm accessing my API from Vue.js project and get the token after the login. But I don't know how to use the token for checking if user is authenticated or not. What's the workaround?
Here's the Vue.js login() method:
login() {
if(this.credentials.login && this.credentials.password) {
axios.post('http://localhost:8000/api/login', this.credentials)
.then(response => {
if(response.data.success) {
this.token = response.data.token;
}
})
.catch(error => {
console.log(error);
});
}
}
Here's the
/**
* API Login
*
* #param Request $request
* #return \Illuminate\Http\JsonResponse
*/
public function login(Request $request)
{
$credentials = $request->only('login', 'password');
$validator = Validator::make($credentials, [
'login' => 'required|min:4',
'password' => 'required|min:6'
]);
if($validator->fails()) {
$error = $validator->messages()->toJson();
return response()->json([ 'success' => true, 'error' => $error ]);
}
try {
if(!$token = JWTAuth::attempt($credentials)) {
return response()->json([
'success' => false,
'error' => 'Неверные логин или пароль.'
], 401);
}
} catch (JWTException $e) {
return response()->json([
'success' => false,
'error' => 'Не удалось создать токен.'
], 500);
}
return response()->json([
'success' => true,
'token' => $token
]);
}
By the way, API is running on http://localhost:8000/ and Vue.js project on http://localhost:8080/
You can include the token in each subsequent request after you authorize the user and get the token, there is few places you can include the token, in a request after ?token=<token> as a request param, inside of a header under Authorization: Bearer {token} and how to get the Authenticated user from that token you can check on official docs which gives you a concrete example on how to.
I am building a project using laravel which is simple api i have built using passport and on the frontend i am using react everything works fine except that i can't catch the error messages in the .catch function i can see the errors in the network tab of my browser but i cant figure out how to display them.
here is my UserController
class UserController extends Controller
{
public function create(Request $request)
{
$data = $request->only('name', 'email', 'password');
$validator = Validator::make($data, [
'name' => 'required',
'email' => 'required|email|unique:users',
'password' => 'required|min:6'
]);
if ($validator->fails()) {
return response()->json(['errors'=>$validator->errors()], 422);
}
$user = User::create([
'name' => $data['name'],
'email' => $data['email'],
'password' => bcrypt($data['password'])
]);
}
}
and this how i consume the api using axios:
export function signupUser({ name, email, password }) {
return function(dispatch) {
axios.post(`${ROOT_URL}/api/signup`, {name, email, password})
.then(response => {
dispatch({ type: AUTH_USER });
localStorage.setItem('token', response.data.access_token);
browserHistory.push('/feature');
})
.catch((error) => {
// console.log(error);
});
}
}
and here is the console log
and here is the response in the network tab of my browser
If you have any question please let me know.
Any help will be appreicated
Change the following lines of code.
.catch((error) => {
console.log(error.response);
});
.catch(function (error) {
if (error.response) {
// The request was made, but the server responded with a status code
// that falls out of the range of 2xx
console.log(error.response.data);
console.log(error.response.status);
console.log(error.response.headers);
} else {
// Something happened in setting up the request that triggered an
console.log('Error', error.message);
}
return error;
});
Please check the below code
https://github.com/johibkhan2/react-redux-singlePageApp/blob/master/app/api/phone-api.js