I want to implement Passport authentication in Laravel. this is the register function:
public function register(Request $request)
{
$credentials = $request->only('name', 'email', 'password');
$rules = [
'name' => 'required|max:100',
'email' => 'required|email|max:120|unique:users',
'password' => 'required',
];
$validator = Validator::make($credentials, $rules);
if($validator->fails()) {
return response()->json(['success'=> false, 'error'=> $validator->errors()]);
}
$user = User::create(['name' => $request->name, 'email' => $request->email, 'password' => bcrypt($request->password)]);
if(Auth::attempt($credentials)){
$user = Auth::guard('api')->user();
$data['id'] = $user->id;
$data['name'] = $user->name;
$data['phone'] = $user->phone;
$data['token'] = $user->createToken('API')->accessToken;
return response()->json([
'success'=> true,
'data'=> $data
]);
}
return response()->json([
'success'=> false,
'data'=> $response
]);
}
and this is my routes:
Route::post('register', 'Api\AuthController#register');
Route::middleware('auth:api')->get('/user', function (Request $request) {
return response()->json($request->user());
});
I want to display the user information in postman, and this is the request header to the url: http://127.0.0.1:8004/api/user:
Accept:application/json
Authorization:Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJhdWQiOiIxIiwianRpIjoiOThjYjM0YjkzOWJhMzczMDEwMGI0NmEyNTBhOGEzYTc5MTAyMjI1M2E2OTM0OGY0NGU1YWU4Njg3MzZkYmVlZjNlNzI1MDNiZTRhMjE5NGUiLCJpYXQiOjE1ODQ1NDczMDcsIm5iZiI6MTU4NDU0NzMwNywiZXhwIjoxNjE2MDgzMzA3LCJzdWIiOiI1NyIsInNjb3BlcyI6W119.GcqelFT2d3kKi8fR2vNbgMB1Fe_sQjrd2Mb3cRQLbS20IR_445bcTbcl17yKJrldboFktobeSIHx1GQENIzQbO0RStysmisiKuLk8eoXUvNVJq3t1bpZrjPBiNEGDRPqezq5VEsGhotVgbKRLK1gbVHwvE7mtSuGQTp9nIf6PEsmiJLsGmUJ0GdCmWXXLvJ0dBac1DZ_KauppDs_Lymx9SEXgzTDW60rpYrwHNbbaLfa6wdW3M5tUZM3vMRcKhCgYitvK_DfttKHcWqvEX8_lZT0h5GcQSsori_K8Lj_ynKfjrTfbodUKzT4kDZ8z-RnE4-SgG75LWDeqcpDRhuDmiL0KTIzwtrNFtU0NEo-v0t6dTkAuJCl1ZnTT72sLZoI6rsTPHtNKIDxwN9VrXiTU5pxGEc6ju5e30NQnkjBRjMRsVIcCHR-WohObuWkZOGRq-RP5on3oiLe2VGk0PENXXziMX3D5urpLWK3WR-ZY0Bz3fKitgE8TFaT1cOMSyK6d3zskUEdMjDyLCxbS7vKhmNuAy2moOj7f7DI9yr8XNeyF00WJKw0WJi76XX_Y06O-VtNhqzgeEyu6QM6qRivpBBcj-WkdbSTmveNZlSqAesLm6WD8qWKc9FR-S_41fCc2qLEY_VOotSA8tOYASVKpdsvj2liTbbMH9905HQJe-o
Content-Type:application/json
but the result is always:
{
"message": "Unauthenticated."
}
How could I display user information? thanks in advance
Change
Auth::attempt($credentials)
to
Auth::guard('api')->attempt($credentials)
Related
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);
}
I am using the latest version of Laravel Sanctum to create a validation method for my SPA, but I ran into an issue(notice that I dont work that long with laravel). When I login it works, but when I logout and try to login it stops working. After some testing I noticed that this was because of a cookie that was added by laravel.
// loginController
public function login(Request $request)
{
if ($this->validator($request->all())->fails()) {
//validation stuff
} else {
$credentials = [
'email' => $request->email,
'password' => $request->password,
];
$user = User::where('email', $request->email)->firstOrFail();
if (auth()->attempt($credentials)) {
$token = $user->createToken('auth')->plainTextToken;
$response_code = 200;
$response = [
'user' => $user,
'success' => true,
'errors' => false,
'message' => 'Login successfully',
'access_token' => $token,
'token_type' => 'Bearer',
];
} else {
$response_code = 422;
$response = [
'success' => false,
'errors' => [],
'message' => 'Invalid login'
];
}
}
public function logout(Request $request)
{
$request->user()->tokens()->delete();
}
I was recently updating from laravel's sanctum to passport; and there is this one test that bothers me a lot.
In sanctum there is this method under the PersonalAccessToken model that finds the token and returns the token if it exists.
I don't seem to find anything like that in the docs or online.
I'm validating the test by asserting that $user->tokens is not empty... yet I wish to validate that the token I'm returning from my login controller is indeed a token; not just the creation;
Thnx in advance...
Login Test
public function user_can_login()
{
//$this->withoutExceptionHandling();
$user = User::factory()->create();
$url = route('api.v1.auth.login', [
'email' => $user->email,
'password' => 'password'
]);
$res = $this->jsonApi()
->post($url)
->assertStatus(200);
$token = $res->json(['access_token']);
$this->assertNotEmpty($user->tokens);
}
Login method in authcontroller
public function login(Request $request)
{
$request->validate([
'email' => 'required|email',
'password' => 'required',
]);
$credentials = $request->only(['email', 'password']);
if (Auth::attempt($credentials)) {
$user = Auth::user();
$access_token = $user->createToken('laravel-api.local')->accessToken;
return response()->json(['access_token' => $access_token], 200);
} else {
return response()->json(['error' => 'Unauthorized'], 401);
}
}
pues:dont know why im writing the code, but just for ref of what i'm doing
https://laracasts.com/discuss/channels/testing/how-do-i-create-a-route-while-testing
solution is quite simple... you'll find it here... I had an issue when I tried that before hand and it seems to be with the use of the Route::name('name') method and the route('name') function threw a server error. but if you call the path directly it should work...
any who... authController and login method stay the same but the test changes to...
public function setUp(): void
{
parent::setUp();
Route::middleware('auth:api')
->get('/test-route', function (Request $request) {
return $request->user();
});
$clientRepository = new ClientRepository();
$client = $clientRepository->createPersonalAccessClient(
null,
'Personal Access Client Test',
'/'
);
DB::table('oauth_personal_access_clients')->insert([
'client_id' => $client->id,
'created_at' => date('Y-m-d'),
'updated_at' => date('Y-m-d'),
]);
}
/** #test */
public function user_can_login_with_correct_credentials()
{
//$this->withoutExceptionHandling();
$user = User::factory()->create();
$url = route('api.v1.auth.login', [
'email' => $user->email,
'password' => 'password',
'device_name' => $user->name . ' test Device'
]);
$res = $this->jsonApi()
->post($url)
->assertStatus(200);
$token = $res->json(['access_token']);
$this->jsonApi()
->withHeader('Authorization', 'Bearer ' . $token)
->get('/test-route')
->assertStatus(200);
}
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);
}
My form validation is not working in Laravel. How can I update my form with validation in Laravel?
You can check my code here-
public function update(Request $request, $id)
{
$id->validate([
'Name'=>'required',
'UserName'=>'required',
'Password'=>'required|min:6',
'email'=>'required|email',
]);
$updateInfo= Info::findOrFail($id);
$updateInfo->user_id = $request->input('user_id');
$updateInfo->Name = $request->input('Name');
$updateInfo->UserName = $request->input('UserName');
$updateInfo->Password = $request->input('Password');
$updateInfo->save();
return redirect('/info');
}
You need to call validate on $request, like this-
$request->validate([
'Name'=>'required',
'UserName'=>'required',
'Password'=>'required|min:6',
'email'=>'required|email',
]);
Here is the full code-
public function update(Request $request, $id)
{
$request->validate([
'Name'=>'required',
'UserName'=>'required',
'Password'=>'required|min:6',
'email'=>'required|email',
]);
if (!$validator->fails()) {
$updateInfo= Info::findOrFail($id);
$updateInfo->user_id = $request->input('user_id');
$updateInfo->Name = $request->input('Name');
$updateInfo->UserName = $request->input('UserName');
$updateInfo->Password = $request->input('Password');
$updateInfo->save();
} else {
\Session::flash('error', $validator->messages()->first());
return redirect()->back()->withInput();
}
return redirect('/info');
}
I have added one more condition in the code to handle the validation errors. If validation fails then it will redirect back with your inputs as well as the validation error messages. Make sure you have error session flash in your blade views to show the errors.
For me this is best way , i can keep on track on query and other exceptions by putting it in try catch block
public function update(Request $request, $id)
{
try{
$validator = Validator::make($request->all(), [
'name' => 'required',
'UserName' => 'required',
'Password' => 'required',
'email' => 'required|email',
]);
if($validator->fails()) {
return redirect()
->route('path_to_edit_form')
->withErrors($validator)
->withInput();
}
Info::where('id',$id)->update([
'user_id' => $request->get('user_id'),
'Name' => $request->get('Name'),
'UserName' => $request->get('UserName'),
'Password' => $request->get('Password'),
]);
return back()->with([
'alert_type' => 'success',
'message' => 'User info updated successfully.'
]);
}catch(\Exception $e){
return back()->with([
'alert_type' => 'danger',
'message' => $e->getMessage()
]);
}
}