I'm working on a Laravel API and using Postman to test it,
I have a route /api/login that authenticates the user and return a token.
Route::post('login', [ApiAuthenticationController::class, 'login']);
The Login Method:
class ApiAuthenticationController extends Controller
{
/**
* Api user login
*
* #param Request $request
* #return JsonResponse
*/
public function login(Request $request): \Illuminate\Http\JsonResponse
{
$credentials = $request->only('username', 'password');
if (Auth::attempt($credentials)) {
$user = Auth::user();
$token = $user->createToken('token')->accessToken;
return response()->json([
'token' => $token,
]);
}
return response()->json([
'error' => 'Invalid username or password',
], 401);
}
}
here's the the response:
Login Api Response
When I try to send a request to a route let's say: api/v1/admin/proposals with the Barear token that I retrieved, I get 403 forbidden and the message USER NOT LOGGED IN
Route::group(['prefix' => 'v1', 'namespace' => 'App\Http\Controllers\Api\V1'], function () {
Route::middleware(["role:admin"])->prefix('admin')->group(function () {
Route::resource('proposals', AdminProposalController::class);
});
});
admin/proposals Response
Note that the user has the role of admin, and I have Laravel/Passport installed.
is there any parameter to change inside postman?
Related
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.
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'm wondering how to implement tymon jwt 1.0.0 rc2 with Cartalyst Sentinel 2.0 authentication package in Laravel 5.6 to take advantage of throttling and others Sentinel features.
Inside AuthController I have this login() method as mentioned in jwt-auth Docs enter link description here to validate the credentials and generate a token.
public function login()
{
$credentials = request(['email', 'password']);
if (! $token = auth()->attempt($credentials))
return response()->json(['error' => 'Unauthorized'], 401);
return $this->respondWithToken($token);
}
What I did is the following
public function login()
{
$credentials = request(['email', 'password']);
if (! Sentinel::authenticate($credentials))
return response()->json(['error' => 'Unauthorized'], 401);
$token = auth()->attempt($credentials);
return $this->respondWithToken($token);
}
But i don't think this is the right way because there is a double authentication, first by Sentinel and the second by jwt. and this is bad for performance.
And second workaround is to modify attempt() method inside JWTGuard class that resides in vendor/tymon/jwt-auth/src folder.
the default is the following
public function attempt(array $credentials = [], $login = true)
{
$this->lastAttempted = $user = $this->provider->retrieveByCredentials($credentials);
if ($this->hasValidCredentials($user, $credentials)) {
return $login ? $this->login($user) : true;
}
return false;
}
and I changed it like this
public function attempt(array $credentials = [], $login = true)
{
if ($user = Sentinel::authenticate($credentials)) {
return $this->login($user);
}
return false;
}
I don't now if this is a right solution or not ?
Just use auth('api')->user() to get user using jwt or passport with sentinel
in jwt config change with this
'auth' => Tymon\JWTAuth\Providers\Auth\Sentinel::class,
And in auth controller you can used this function
use Tymon\JWTAuth\Facades\JWTAuth;
/**
* Handle a login request to the application.
*
* #param loginRequest $request
*
* #return \Illuminate\Http\RedirectResponse|\Illuminate\Http\Response|\Illuminate\Http\JsonResponse
*/
public function login(loginRequest $request) {
$credentials = array(
'email' => $request->email,
'password' => $request->password,
);
if (! $token = JWTAuth::attempt($credentials)) {
return response()->json(['error' => 'Unauthorized'], 401);
} else {
return $this->respondWithToken($token);
}
}
/**
* Get the token array structure.
*
* #param string $token
*
* #return \Illuminate\Http\JsonResponse
*/
protected function respondWithToken($token)
{
return response()->json([
'access_token' => $token,
'token_type' => 'bearer',
'expires_in' => auth('api')->factory()->getTTL() * 60
]);
}
And now you can logged in.
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.