How can I delete the token when the user log out? - laravel

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();
}
}

Related

Return to a View from Controller after an Api call - Laravel 8

So guys,
I have an app that needs to login.
After login and getting the API and token, it has to redirect to a dashboard, but unfortunately, I can't make it to a dashboard view.
I try to find answers on the forum but can't find one that suits my code.
Here is my api.php
Route::post('/login', App\Http\Controllers\api\LoginController::class)->name('login');
my web.php
Route::get('/dashboard', [Controller::class, 'dashboard']);
my LoginController
class LoginController extends Controller
{
/**
* Handle the incoming request.
*
* #param \Illuminate\Http\Request $request
* #return \Illuminate\Http\Response
*/
public function __invoke(Request $request)
{
//set validation
$validator = Validator::make($request->all(), [
'email' => 'required',
'password' => 'required'
]);
//if validation fails
if ($validator->fails()) {
return response()->json($validator->errors(), 422);
}
//get credentials from request
$credentials = $request->only('email', 'password');
//if auth failed
if(!$token = auth()->guard('api')->attempt($credentials)) {
return response()->json([
'success' => false,
'message' => 'Email atau Password Anda salah'
], 401);
}
//if auth success
return response()->json([
'success' => true,
'user' => auth()->guard('api')->user(),
'token' => $token
], 200);
}
my AuthController :
class AuthController extends Controller
{
public function login(Request $request){
$email = $request->input("email");
$password = $request->input("password");
$request = Request::create('http://localhost:8000/api/login', 'POST',[
'name'=>$email,
'password'=>$password,
]);
$response = json_decode(Route::dispatch($request)->getContent());
// echo($response->success);
if($response->success == 1 || true){
return redirect()->route('dashboard',["response"=>$response]);
}else{
return redirect()->back();
}
}
}
Controller.php where dashboard route is defined:
public function dashboard()
{
return view('dashboard', [
"title" => "Dashboard",
]);
}
if I'm using this code, the error I get is:
Route [dashboard] not defined.
but if I'm not using return redirect and use return view instead. I can go to my dashboard, but the URL is localhost:8000\auth\login which is not what I want.
is there any suggestion so I can get my view on Dashboard?
Thank you very much.

How to check if the user is admin in Laravel?

As a checklogin function in my Controller I have
public function checkLogin(Request $request)
{
//if the validation rule isn't passed it will be redirected to login form with validation error
$this->validate($request, [
'email' => 'required|email',
'password' => 'required|min:3'
]);
$user_data = array(
'email' => $request->get('email'),
'password' => $request->get('password'),
);
if (Auth::attempt($user_data)) {
return redirect('/successlogin');
//user will be redirected to successlogin method
} else {
return back()->with('error', 'Wrong Login Details');
//by using back() he will be redirected to the previous location
}
}
And I added a $table->boolean('is_admin')->default(0); column to my model
Also I've tried to make a middleware. Something like
IsAdmin.php
public function handle($request, Closure $next)
{
if (Auth::user()) {
if (Auth::user()->is_admin) {
return $next($request);
}
return Redirect::to('successlogin');
}
}
But it throws me an error
"Call to a member function send() on null"
Thanks a lot in advance!

Passport, Method to refresh token after expiring

I'm using laravel v5.8, VueJS and passport v7.4 for Authentication.
Below is my login function:
public function login(Request $request)
{
$validator = Validator::make($request->all(), [
'email' => 'required|string|email',
'password' => 'required|string',
]);
if ($validator->fails()) {
return response([
'status' => 0,
'message' => $validator->errors()->first()
]);
}
$credentials = request(['email', 'password']);
if (!Auth::attempt($credentials))
return response()->json([
'status' => 0,
'message' => 'Unauthorized'
], 401);
$user = $request->user();
$tokenResult = $user->createToken('authToken');
$token = $tokenResult->token;
$token->save();
$user_role = Auth::user()->user_type;
$user->assignRole($user_role);
return response()->json([
'status' => 1,
'access_token' => $tokenResult->accessToken,
'token_type' => 'Bearer',
'expires_at' => Carbon::parse(
$tokenResult->token->expires_at
)->toDateTimeString(),
]);
}
My issue is my token expires in 10 seconds(this is for testing purpose). So I check for every route if the token is expired using the below function in VueJS:
isValid(token) {
const payload = this.payload(token);
if (payload) {
const datetime = Math.floor(Date.now() / 1000);
return payload.exp >= datetime ? true : false;
}
return false;
}
So this works fine, but what should i do to refresh the token?
Can we make a middleware to handle it by itself?
Or Is there anyway to detect if the user is actively using the application like
in normal session based authentication?
Looks like you are reinventing the wheel, I would recommend to make a request to passport /oauth/token which will then return the access_token and refresh token. Also to get away with a build authentication control layer I am using nuxtjs.
The below example requires guzzlehttp/guzzle package.
<?php
namespace App\Http\Controllers\Api;
use App\Http\Controllers\Controller;
use App\Http\Resources\User;
use Illuminate\Http\Request;
use GuzzleHttp\Client;
class AuthController extends Controller
{
/**
* #param Request $request
* #return \Illuminate\Http\JsonResponse
*/
public function user(Request $request)
{
return response()->json(['user' => new User($request->user())]);
}
/**
* #param Request $request
* #return \Illuminate\Http\JsonResponse|\Psr\Http\Message\StreamInterface
*/
public function login (Request $request)
{
$http = new Client;
try {
$response = $http->post(config('app.url') . '/oauth/token', [
'form_params' => [
'grant_type' => 'password',
'client_id' => '2',
'client_secret' => 'ugjAn1BD4Cs8gAP63RqixyCOD3Z1dUrrNiEgxQtN',
'username' => $request->get('email'),
'password' => $request->get('password')
]
]);
return $response->getBody();
} catch (\GuzzleHttp\Exception\BadResponseException $e) {
if (400 === $e->getCode()) {
return response()->json(['message' => 'Invalid request. Please enter username and password'], $e->getCode());
} else if (401 === $e->getCode()) {
return response()->json([message' => 'Your credentials are incorrect. Please try again.'], $e->getCode());
}
}
return response()->json(['message' => 'Something went wrong please try again later. ' . $e->getMessage()], $e->getCode());
}
/**
* #param Request $request
* #return \Illuminate\Http\JsonResponse
*/
function logout (Request $request)
{
$request->user()->tokens->each(function ($token, $key) {
$token->delete();
});
return response()->json(['message' => 'Logged out successfully'], 200);
}
}

Redirect to view after API login using Passport

I added API authentication to my Laravel app using passport. I followed this tutorial:
https://medium.com/techcompose/create-rest-api-in-laravel-with-authentication-using-passport-133a1678a876
Now how do I redirect to a view after the user is been authenticated? I need this to embed my webapp to another portal using single sign on.
This returns the user values:
public function details()
{
$user = Auth::user();
return response()->json(['success' => $user], $this->successStatus);
}
This tells me the user is unauthorized:
public function details()
{
$user = Auth::user();
return redirect('/home');
}
This is my route:
Route::post('details', 'API\UserController#details')->middleware('auth:api');
This is my login:
public function login(){
if(Auth::attempt(['email' => request('email'), 'password' => request('password')])){
$user = Auth::user();
$success['token'] = $user->createToken('MyApp')->accessToken;
return response()->json(['success' => $success], $this-> successStatus);
}
else{
return response()->json(['error'=>'Unauthorised'], 401);
}
}
You can validate user after
Auth::attempt(['email' => request('email'), 'password' => request('password')])
if(Auth::check())
return redirect()->route('<route_name>');

Redirect to profile page after authentication in laravel

When a user logs in I want them to be redirected to their profile page instead of homepage. I have a method in another controller that gets a user profile. Not sure what I need to do since the user profile takes a username variable but when user logs in I'm only asking for email and password.
My route file, but the following method is in a different controller from the authentication controller.
Route::get('/user/{username}', [
'uses' => 'ProfileController#getProfile',
'as' => 'profile.index',
'middleware' => ['auth'],
]);
My following method is in my authentication controller.
public function postSignin(Request $request)
{
$this->validate($request, [
'email' => 'required',
'password' => 'required',
]);
if (!Auth::attempt($request->only(['email', 'password']), $request->has('remember'))) {
return redirect()->back()->with('info' , 'Could not sign you in with that info.');
}
$user= User::where('username', $username)->first();
return redirect()->route('profile.index')
->with('info', 'You are now signed in.')
->with('user', $user);
}
The following is in my profile controller..
public function getProfile($username)
{
$user= User::where('username', $username)->first();
if (!$user){
abort(404);
}
return view('profile.index')
->with('user', $user);
}
To correctly build the route, you need to pass the username here:
$user = User::where('username', $username)->first();
return redirect()->route('profile.index', ['username' => $user->username])
->with('info', 'You are now signed in.')
->with('user', $user);
Get the username from the email provided and pass the $username variable to route:
public function postSignin(Request $request)
{
if (!Auth::attempt($request->only(['email', 'password']),$request->has('remember')))
{
return redirect()->back()->with('info' , 'Could not sign you in with that info.');
}
$username=User::where(['email'=>$request->email])->first()->username;
return redirect()->route('profile.index')->with('username', $username);
}
You can use as like below.
if (!Auth::attempt($request->only(['email', 'password']), $request->has('remember'))) {
return redirect('profile.index')->with('info' , 'Could not sign you in with that info.');

Resources