I am developing in Laravel 5.3.
When reviewing the routes, I have the following:
Here it indicates that my routes are POST. But if in Postman I enter the URL (POST), I throw the following error
The strangest thing is that on my local server it works fine, this error occurred to me on the production server.
My code is:
api.php
Route::group(['middleware' => ['api', 'auth:api']], function() {
require_once 'Routes/Api/ProductRoute.php';
});
routes/Routes/Api/UserRoute.php
<?php
Route::post('user/authenticate', [
'as' => 'api.user.authenticate',
'uses' => 'Api\UserController#authenticate'
]);
Route::post('user/register', [
'as' => 'api.user.register',
'uses' => 'Api\UserController#register'
]);
/app/Http/Controllers/Api/UserController.php
public function authenticate(Request $request)
{
$credentials = $request->only('email', 'password');
if (Auth::attempt($credentials)) {
$user = Auth::user();
\DB::table('oauth_access_tokens')
->where('user_id', $user->id)
->where('name', $request->platform)
->update(['revoked' => 1]);
$token = $user->createToken($request->platform)->accessToken;
return Controller::apiResponse(1, compact('user', 'token'));
} else{
return Controller::apiResponse(-1);
}
}
Related
I made a manual login system in a Laravel 9 API that it's works correctly, but when I try to use Auth::user() in another controller, I get it as null, but when I return the auth->user() to the Vue SPA, I get it correctly. Is there a way to it is setting Auth::user() null after a successfull login? Here's are my api.php (api routes):
route::middleware('auth:sanctum')->get('/user', function (Request $request) {
return $request->user();
});
route::controller(UserController::class)->group(function () {
route::post('/register', 'register');
route::post('/login', 'login');
route::get('/logout', 'logout');
});
route::resource('book', BookController::class);
route::get('/my_books/{user_id}', [BookController::class, 'myBooks']);
As you can see in the image above, I can get the authenticated user after try login it, here's my login method:
public function login(Request $request)
{
$validate = $request->validate([
'email' => 'required|email',
'password' => 'required'
]);
if ($validate) {
$credentials = $request->only('email', 'password');
return Auth::attempt($credentials)
? Auth::user() :
response()->json('No se ha podido iniciar sesión', 500);
}
return response()->json($validate->errors, 422);
}
But when I'm going to store a new book, I get the following error:
Here's the error, when I try to use the auth()->user() method to get the logged in user's id:
public function store(Request $request)
{
$validate = $request->validate([
'title' => 'required',
'genre' => 'required'
]);
if ($validate) {
$book = Book::create([
'title' => $request->title,
'author' => $request->author,
'genre' => $request->genre,
'subgenre' => $request->subgenre,
'opinion' => $request->opinion,
]);
$user = User::find(auth()->user()->id);
if ($request->cover) {
$this->uploadImage($request, 'cover', $book);
}
$user->books()->save($book);
return new BooksResource($book);
}
I don't know why it's happening, and I'd like any idea or possible solution. Thanks in advance:
From laravel 9 documentation
// Get the currently authenticated user's ID...
$id = Auth::id();
Also, you should describe your
route::get('/my_books/{user_id}', [BookController::class, 'myBooks']);
route before resource route.
I guess, you dont need this assign $user = User::find(auth()->user()->id); just use auth()->user
To get the Authenticated user, put the book route inside the auth:sanctum middleware.
When the user created a new account I added it's API token and returned it to the user. But I'm having trouble wanting to return the API token to the user when they view their account information.
GET /account: Returns API Token in response.
This is my code file User.php:
public function index()
{
$users = User::where('id', auth()->user()->id)->get();
return response([
'data' => UserResource::collection($users),
'message' => 'Retrieve successfully'
], 200);
}
// POST
public function store(Request $request)
{
$data = $request->all();
$validator = Validator::make($data, [
'name' => 'required|max:255|string',
'email' => 'required|email|unique:users,email',
'password' => 'required|string',
]);
if ($validator->fails()) {
return response(['error' => $validator->errors(), 'Validation Error'], 400);
}
$users = User::create($data);
$token = $users->createToken('accessToken')->plainTextToken;
return response([
'data' => new UserResource($users),
'api_token' => $token,
'message' => 'Created successfully'
], 201);
}
This is my code file api.php (route):
Route::group(['prefix' => 'v1' ], function () {
// Account
Route::post('/account', [UserController::class, 'store']);
// Protected route
Route::group(['middleware' => ['auth:sanctum']], function () {
// Account
Route::get('/account', [UserController::class, 'index']);
});
});
Use $request->bearerToken() to get bearer token.
public function index()
{
$users = User::where('id', auth()->user()->id)->get();
return response([
'data' => UserResource::collection($users),
'api_token' => $request->bearerToken(),
'message' => 'Retrieve successfully'
], 200);
}
As the title says CreateFreshApiToken doesnt create any cookies. So I cant use it to auth a logged in user for other requests related to the user.
I tried to set a cookie on the response and it works perfectly fine. So this has to do something with CreateFreshApiToken not working.
AuthController.php
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use App\User;
class AuthController extends Controller
{
public function signup(Request $request)
{
$request->validate([
'name' => 'required|string',
'email' => 'required|string|email|unique:users',
'password' => 'required|string'
]);
$user = new User([
'name' => $request->name,
'email' => $request->email,
'password' => bcrypt($request->password)
]);
$user->save();
return response()->json([
'message' => 'Successfully created user!'
], 201);
}
public function signin(Request $request)
{
$request->validate([
'email' => 'required|string|email',
'password' => 'required|string'
]);
$credentials = request(['email', 'password']);
if(!Auth::attempt($credentials))
return response()->json([
'message' => 'Unauthorized'
], 401);
$user = $request->user();
$tokenResult = $user->createToken('Personal Access Token');
$token = $tokenResult->token;
$token->save();
return response()->json([
'message' => 'Successfully signed in!'
]);
}
public function signout(Request $request)
{
$request->user()->token()->revoke();
return response()->json([
'message' => 'Successfully signed out!'
]);
}
public function user(Request $request)
{
return response()->json($request->user());
}
public function test()
{
return response()->json([
'message' => 'test'
]);
}
public function test2(Request $request)
{
return response()->json([
'laravel_token' => $request->cookie('laravel_token')
]);
}
}
Kernel.php
protected $middlewareGroups = [
'web' => [
//...
\Laravel\Passport\Http\Middleware\CreateFreshApiToken::class,
],
'api' => [
'throttle:60,1',
'bindings',
\Barryvdh\Cors\HandleCors::class,
],
];
api.php
Route::group([
'prefix' => 'auth'
], function () {
Route::post('signin', 'AuthController#signin');
Route::post('signup', 'AuthController#signup');
Route::get('test', 'AuthController#test');
Route::get('test2', 'AuthController#test2');
Route::group([
'middleware' => ['auth:api']
], function() {
Route::get('signout', 'AuthController#signout');
Route::get('user', 'AuthController#user');
});
});
And this is my angular code:
test() {
return this.http.get('http://homestead.test/api/auth/test', {withCredentials: true})
.subscribe(response => {
console.log(response);
});
}
test2() {
return this.http.get('http://homestead.test/api/auth/test2', {withCredentials: true})
.subscribe(response => {
console.log(response);
});
}
I've also setup cors with https://github.com/barryvdh/laravel-cors successfully with 'supportsCredentials' enabled. I am also sending a useless GET request to see if any laravel_token is set in the cookie but no success.
CreateFreshApiToken is part of the web middleware group, so in order for it to set cookies you need your login page to be a web route (instead of an api route).
I resolved this part of the problem by replicating CreateFreshApiToken::handler in my login controller:
$response = response()->json([], 200);
// ADD THIS LINE:
$response->cookie(\Laravel\Passport\Passport::cookie(),$request->session()->token();
return $response;
I'm trying to figure out how to test my Passport-driven logout function, which looks like this:
public function logout() {
$accessToken = auth()->user()->token();
$refreshToken = DB::table('oauth_refresh_tokens')
->where('access_token_id', $accessToken->id)
->update([
'revoked' => true
]);
$accessToken->revoke();
return response()->json(['status' => 200]);
}
I am using the Passport actingAs helper in setting up the response.
Passport::actingAs(
$user,
['read write']
);
$response = $this->post('/logout')
->assertStatus(200);
The test fails, as the code gives a 500 error, as auth()->user()->token() is ... empty-ish? $accessToken->id is 0, for example, which it shouldn't be, which means the code fails.
What I'm not sure about is if this is expected behavior because of how Passport's actingAs helper works and I can't actually test the logout function, or if there's something wrong with my logout function. Halp!
My routes:
Route::post('login', 'Auth\LoginController#login');
Route::group(['middleware' => 'auth:api'], function() {
Route::post('logout', 'Auth\LoginController#logout');
});
Route::middleware('auth:api')->get('/user', function (Request $request) {
return $request->user();
});
JsonApi::register('v1', ['namespace' => 'Api'], function (Api $api, $router) {
$api->resource('training-locations');
$api->resource('courses');
});
ETA: My login function, if it's helpful:
public function login(Request $request, Client $client){
$this->validateLogin($request);
if ($this->hasTooManyLoginAttempts($request)) {
$this->fireLockoutEvent($request);
return $this->sendLockoutResponse($request);
}
$response = $client->post(config('app.url') . '/oauth/token', [
'form_params' => [
'client_id' => config('auth.proxy.client_id'),
'client_secret' => config('auth.proxy.client_secret'),
'grant_type' => config('auth.proxy.grant_type'),
'username' => $request->email,
'password' => $request->password,
'scopes' => '[read write]'
]
]);
if ($response->getStatusCode() === 200) {
$this->clearLoginAttempts($request);
return response($response->getBody()->getContents(), $response->getStatusCode());
}
$this->incrementLoginAttempts($request);
return response($response->getBody()->getContents(), $response->getStatusCode());
}
In order to investigate if this is actually an issue, I tried hitting the endpoint via Postman. It gets into the function, but it does not find the auth()->user(). I tried some other endpoints using the same route group, and it was able to find the auth()->user() with them. What might cause it to go missing like that?
It's a little late, but maybe someone will find it helpful. In order to test the logout function you have provided you'll need to pass the token as authorization header.
$response = $this->post('/logout', [], ['Authorization' => 'Bearer ' . $token])
->assertStatus(200);
I'm not sure why, but the access token can't be retrieved with $user->token() when using actingAs, but it can be retrieved with $user->tokens()->first()
.
i have problem in submitting this form it produces NotFoundHttpException
{{Form::open(array('parsley-validate'=>'','url'=>url('dashboard/send_message')))}}
this is the function the form should execute in dashHome.php in dashboard folder
public function postSendMessage()
{
$validator = Validator::make(Input::all(), array(
'studentId' => 'required|exists:student,id',
'content' => 'required',
));
if ($validator->fails())
return Redirect::to('dashboard')->withErrors($validator);
$user = Auth::user();
$user->decrement('sms_credit');
return Redirect::to('dashboard')->with('messageSent',1);
}
this is the route in route.php
Route::group(array('prefix' => 'dashboard','before'=>'auth'), function() {
Route::get('/', 'dashHome#index');
});
You need to define a route for the url dashboard/send_message in your routes.php file, like this:
Route::group(array('prefix' => 'dashboard','before'=>'auth'), function()
{
Route::get('/', 'dashHome#index');
Route::post('send_message', 'dashHome#postSendMessage');
});