I am implementing an Authentication api in Laravel using passport.
I have implemented the login api, but there is a problem with logout api. My login code is working successfully:
public function login(Request $request){
$request->validate([
'email'=> 'required|string|email',
'password'=> 'required|string',
'remember_me'=> 'boolean',
]);
$credentials= request(['email','password']);
if(!Auth::attempt(['email' => $request->email, 'password' => $request->password])){
return response()->json([
'message'=> 'Unauthorized'
],401);
}
Auth::attempt(['email' => $request->email, 'password' => $request->password]);
$user=$request->user();
$tokenResult = $user->createToken('Personal Access Token');
$token = $tokenResult->token;
if($request->remember_me)
$token->expires_at= Carbon::now()->addWeek(1);
$token->save();
return response()->json([
'access_token'=>$tokenResult->accessToken,
'token_type'=>'Bearer',
'expires_at'=>Carbon::parse($tokenResult->token->expires_at)
->toDateTimeString()
]);
}
This works successfully, however, when I use the same bearer token to revoke the token of the user I am receiving the following exception:
Call to a member function token() on null
This is referring to the first line of the logout method below.
public function logout(Request $request){
$request->user()->token()->revoke();
return response()->json([
'message'=> 'Successfully logged out'
]);
}
Why is the output of $request->user() null?
Create a token for the authenticated user, not the guest user who made the request
$user= auth()->user();
$tokenResult = $user->createToken('Personal Access Token');
$token = $tokenResult->accessToken;
And when revoking
public function logout(Request $request)
{
auth()->user()->token()->revoke();
return response()->json([
'message'=> 'Successfully logged out'
]);
}
Hope this helps
Related
I have created a REST API with LARAVEL SANCTUM. I have tested api on postman and it works as expected but when mobile developer uses it on ionic app, it returns for login "TOKEN MISMATCH".
Here is my API route
Route::post('/register', [ApiController::class, 'register']);
Route::post('/login', [ApiController::class, 'login']);
Here is the ApiController for login
public function login(Request $request){
$fields = $request->validate([
'email' => 'required|string|email|max:255',
'password' => 'required|string|min:8'
]);
//validate login parameters
//check email
$user = User::where('email', $fields['email'])->first();
//check password
if(!$user || !Hash::check($fields['password'], $user->password)){
return response([
'message' => 'Invalid Credentials'
], 401);
}
$token = $user->createToken('myapptoken')->plainTextToken;
//return $user->createToken($request->device_name)->plainTextToken;
$response = [
'user' => $user,
'token' =>$token,
];
return response($response, 201);
}
EndPoint: https://findajob.ng/api/login
Email:johndeo1#gmail.com
Password: 12345678
This might not be a problem from backend, but in other-hand, if everything work in postman, you might try to:
Change support_credentials in config\cors to true.
Add withCredential header to front-end.
For my job, I have to make an app which never use the database directly. I have to only request an API even for the connection.
So... There is my problem. I try to make an auth with a user that i'm getting from API but i'm always redirect to the login page.
My API auth :
public function login(Request $request)
{
$credentials = request(['use_username', 'password']);
$this->guard()->factory()->setTTL(config('jwt.ttl') * 12);
if (!$token = $this->guard()->attempt($credentials)) {
return response()->json(['error' => 'Unauthorized'], 401);
}
$user = auth()->user();
return $this->respondWithToken($user, $token);
}
protected function respondWithToken($user, $token)
{
$cookie = cookie('jwt', $token, 60 * 12); // 12h
return response()->json([
'user' => $user,
'token' => $token
])->withCookie($cookie);
}
My web app auth :
public function login(Request $request)
{
$response = Http::post(env('app_url').'/api/auth/login', $request->only('use_username', 'password'));
$cookie = cookie('jwt', $response['token'], 60 * 12); // 12h
$user = ( new User() )->forceFill( $response['user'] );
if (Auth::login($user)) {
$request->session()->regenerate();
return redirect('/');
}
flash('error')->error();
return back()->withErrors([
'email' => 'The provided credentials do not match our records.',
]);
}
My API guard (default guard) :
'api' => [
'driver' => 'jwt',
'provider' => 'users',
'hash' => false
]
The goal is to authenticate the user in the API, get a JWT token and auth the user in the web app with the same user that got in the API. After, all my request to the API have to use the JWT token get during the login... Maybe with a HttpOnly cookie ?
Well, i can't connect my user to the web app, i'm always unauthenticate and redirect to th elogin form, can someone help me ?
I'm using tymon/jwt-auth library with PHP 8
I made a UserController which generats an accessToken when a user registered succesfully on a page.
class UserController extends Controller
{
/**
* Login Method: in here we call Auth::attempt with the credentials the user supplied.
* If authentication is successful, we create access tokens and return them to the user.
* This access token is what the user would always send along with all API calls to have access to the APIs.
* Register Method: like the login method, we validated the user information,
* created an account for the user and generated an access token for the user.
*/
public function login()
{
$credentials = [
'email' => request('email'),
'password' => request('password')
];
if (Auth::attempt($credentials)) {
$success['token'] = Auth::user()->createToken('MyApp')->accessToken;
return response()->json(['success' => $success]);
}
$status = 401;
$response = ['error' => 'Unauthorized'];
return response()->json($response, $status);
}
public function register(Request $request)
{
$validator = Validator::make($request->all(), [
'name' => 'required',
'email' => 'required|email',
'password' => 'required',
]);
if ($validator->fails()) {
return response()->json(['error' => $validator->errors()], 401);
}
$input = $request->all();
$input['password'] = bcrypt($input['password']);
$user = User::create($input);
$success['token'] = $user->createToken('MyApp')->accessToken;
$success['name'] = $user->name;
return response()->json(['success' => $success]);
}
public function getDetails()
{
return response()->json(['success' => Auth::user()]);
}
}
My problem is that I want to remove the token when the user logs out but I dont know how to remove the access token from the user.
logout function in my UserController
public function logout()
{
Auth::user()->tokens->each(function($token, $key) {
$token->delete();
});
return response()->json([
'message' => 'Logged out successfully!',
'status_code' => 200
], 200);
}
When I test it with postman with the GET route: http://127.0.0.1:8000/api/logout. Am I missing something?
UPDATE
Here s my api.php file:
Route::resource('categories', 'App\Http\Controllers\CategoryController');
Route::post('register', 'App\Http\Controllers\UserController#register');
Route::post('login', 'App\Http\Controllers\UserController#login');
/**
* We can group the routes we need auth for
* under common middleware. It secures our routes
*/
Route::group(['middleware' => 'auth:api'], function(){
Route::get('logout', 'App\Http\Controllers\UserController#logout');
});
I am testing it in postman using the route: http://127.0.0.1:8000/api/logout and passing the Bearer token, which I get from the login request, as a value.
It should be POST Request instead of GET request, because your deleting/making change to the database.
The route should look like this:
Route::POST('logout', 'App\Http\Controllers\UserController#logout')->middleware('auth:api');
And the logout method in in UserController should be.
public function logout()
{
auth()->user()->tokens->each(function ($token, $key) {
$token->delete();
});
return response()->json([
'message' => 'Logged out successfully!',
'status_code' => 200
], 200);
}
In your logout function, it should expire the token, not delete it
public function logout(Request $request)
{
$request->user()->token()->revoke();
return response()->json([], Response::HTTP_NO_CONTENT);
}
OR if you wanna expire all his tokens:
use Illuminate\Support\Facades\Auth;
public function logout(Request $request)
{
$userTokens = Auth::user()->tokens();
foreach($userTokens as $token)
{
$token->revoke();
}
}
I made a RegistrationRequest and a LoginRequest and when I register the user I login the user immediatly. But when I try to pass the RegistrationRequest into my LoginRequest I get the following error
Can you not pass requests on to other functions? I did it with normal requests and that worked fine, but I gues the are of the same type.
public function login(LoginRequest $request)
{
$credentials = $request->only('email', 'password');
if ($token = $this->guard()->attempt($credentials))
return $this->respondWithToken($token);
return response()->json(['error' => 'Unauthorized'], 401);
}
public function register(RegistrationRequest $request)
{
$user = User::create([
'user_name' => $request->user_name,
'first_name' => $request->first_name,
'last_name' => $request->last_name,
'email' => $request,
]);
return response()->json([
'success' => true,
'data' => $user,
'meta' => $this->login($request),
], 200);
}
I can find anything on web getting this done. I understand a token has to be generated before a user can login, but is there a way to automatically log in the user after they register? Here my register method.
public function register(Request $request)
{
$v = Validator::make($request->all(), [
'email' => 'required|string|email|unique:users|max:255',
'password' => 'required|min:8|confirmed',
]);
if ($v->fails())
{
return response()->json([
'status' => 'error',
'errors' => $v->errors()
], 422);
}
$user = new User;
$user->email = $request->email;
$user->password = bcrypt($request->password);
$user->save();
return response()->json(['status' => 'success'], 200);
}
You are using JWT tokens so after registration you have to send a token belongs to the user which tells other API that this is the logged-in user.
Generate JWT token and return the response with token
$token = JWTAuth::fromUser($user);
return response()->json(['status' => 'success', 'token' => $token], 200);
you can use below methods
Auth::loginUsingId(1);
or
Auth::login($user);