I know how the basic auth works for sign up/login on Laravel. However, I want to learn setting up how to do user sign up (for Password Grant). I set up Passport (2.0) - Passport Grant, and I can get token; however I couldn't find anything for user signup. Then I found a topic here explaining that I should call the oauth/token internally, but also couldn't figure out how to achieve it exactly.
So what I thought is creating a signup() method in a controller and handle user registration on my own, but then how would I pass necessary data to oauth/token route? Because what Laravel uses for $request is Request $request but what Passport uses is ServerRequestInterface $request and when I vardump the $request on oauth/token's issueToken method, it's totally different Request $request.
// Setup new method
public function signup(Request $request) {
// do validations
// create user
User::create([
'email' => $request->username,
'password' => bcrypt($request->password),
]);
$client = \Laravel\Passport\Client::where('password_client', 1)->first();
$oauthData = [
'grant_type' => 'password',
'client_id' => $client->id,
'client_secret' => $client->secret,
'username' => $request->email,
'password' => $request->password,
'scope' => null
]
// Here, I got confused how to pass this `oauthData` to `issueToken()` route
// and it takes it as `ServerRequestInterface $request`
}
Someone did it likes this here, but no idea how I should exactly implement this approach. Because my /oauth/token route's post method issueToken() is like this:
public function issueToken(ServerRequestInterface $request)
{
return $this->withErrorHandling(function () use ($request) {
return $this->server->respondToAccessTokenRequest($request, new Psr7Response);
});
}
I am very confused and couldn't figure out how to overcome this. What is the right way of handling such scenario where I need to signup users through api?
Related
Hello i'm newbie in laravel. I use for authorization sanctum. But i want that some request can available for authorization user (i use laravel for only api, on front i use angular 2).
web.php:
Route::group(['middleware' => ['auth:sanctum']], function () {
Route::post('api/user-information', function(Request $request) {
return response()->json([ auth()->user()]);
});
// API route for logout user
Route::post('api/logout', [AuthController::class, 'logout']);
});
How can I get access token after success autorization user that i can send request for middleware routes. Because if i have request withous access token i always send null in 'api/user-information'. Please help me resolve this problem.
You could better make a new function in a controller, probably the AuthController. In this function you can validate fields
$validatedData = $request->validate([
'email' => ['required', 'email'],
'password' => ['required'],
]);
With the validated data you can use Auth::login($validatedData);
Source: https://laravel.com/docs/9.x/authentication#login-throttling
Welcome to Laravel! I am assuming you have login method that authenticates user. You can create a token in that method and pass it to your frontend.
public function login(Request $request)
{
$request->validate([
'email' => 'required|email',
'password' => 'required',
]);
$user = User::where('email', $request->email)->first();
if (! $user || ! Hash::check($request->password, $user->password)) {
return ['status'=>0,'message'=>'Invalid Credentials','data'=>[]];
}
$data = [
'user'=>$user,
'token'=>$user->createToken('MyToken')->plainTextToken
];
return ['status'=>1, 'message'=>'Login Successful!', 'data'=>$data];
}
If you just need to pass the token, you can simply return token in the response and then pass it in request header (Authorization) of your Angular applcation to access the API routes protected by Sanctum middleware auth:sanctum
return $user->createToken('MyToken')->plainTextToken;
Also since you are going to use Laravel for API, I would suggest you put all your routes in routes/api.php file.
The routes in routes/api.php are stateless and are assigned the api middleware group. The prefix '/api' is applied to all the routes defined in api.php
You can read more about it in Laravel Documentation
Issuing API Tokens
The Default Route Files
User doesn't stay logged in when I use setIdentity.
$user = $this->Users->get(1);
$this->Authentication->setIdentity($user);
$userInfo = $this->Authentication->getIdentity(); // Returns good.
$this->redirect('Somewhere');
Somewhere:
$userInfo = $this->Authentication->getIdentity(); // Returns null.
I am not using form. There is no POST happening only dynamically setting user based on some algo...
Application.php
public function getAuthenticationService(ServerRequestInterface $request): AuthenticationServiceInterface
{
$service = new AuthenticationService([
'unauthenticatedRedirect' => '/login',
'queryParam' => 'redirect',
]);
/* $fields = [
'username' => 'username',
'password' => 'password'
];
$service->loadIdentifier('Authentication.Password', compact('fields')); */
// Load the authenticators, you want session first
$service->loadAuthenticator('Authentication.Session');
return $service;
}
You are setting the principal information on the Authentication but you loose it on the next request because it's not persisted (I'm sparing you the "http is stateless" song...)
Part of your setIdentity should also be persisting the identity. This can be achieved in different ways:
in the session, when using sessions
in a JWT token, when using tokens
Here is how AuthenticationService does it in persistIdentity. I suggest you also have a look at the JWT auth configuration.
I’ve two Laravel based projects and I want to login with API which the first project provides and use this authentication in the second project.
in the LoginController in second project:
public function login(Request $request)
{
$login_response = Http::post('{first_project_login_api}', [
'data' => [
"email" => $request->input('email'),
"password" => $request->input('password')
]
]);
if ($this->attemptLogin($login_response)) {
return $this->sendLoginResponse($request);
}
}
protected function attemptLogin(Response $response)
{
return $response->object()->status === 200;
}
In the second project, I don't need to database because I want to authentication in the first project but does not seems to be possible!
actually I need to know how to overwrite attemptLogin() function in LoginController.
It would be highly appreciated if anyone can advise me!😊
Instead of using login between application, i would use API keys. The easiest way to get started is to use simple API Authentication.
First create migrations for the user table.
Schema::table('users', function ($table) {
$table->string('api_token', 80)->after('password')
->unique()
->nullable()
->default(null);
});
To get keys, set them on the user either in Tinker, command or creation.
$user->api_token = Str::random(60);
$user->save();
Protect your API routes with a middleware.
Route::middleware('auth:api')->group(function() {
// your routes
});
Calling your api is as simply as.
response = $client->request('POST', $yourRoute, [
'headers' => [
'Authorization' => 'Bearer ' . $yourToken,
'Accept' => 'application/json',
],
]);
This is a fairly basic setup, for production or moving forward you should look into Sanctum or Passport. This is just a good start, from where i feel you are based on your question.
I've been looking all over the internet for 2 days for a solution for my problem to no avail. I'm new to Laravel and API's as a whole, so bear with me.
I've managed to create a working REST API with the use of passport via composer:
The routes in routes/api.php:
Route::post('login', 'PassportController#login');
Route::post('register', 'PassportController#register');
And the controller code for login and register:
public function login(Request $request){
$validator = Validator::make($request->all(), [
'email' => 'required|email',
'password' => 'required'
]);
if ($validator->fails()) {
return response()->json(['error'=>$validator->errors()], 401);
}
if(Auth::attempt(['email' => request('email'), 'password' => request('password')])){
$user = Auth::user();
$success['token'] = $user->createToken('MyApp')->accessToken;
return response()->json(['success' => $success], 200);
}
else{
return response()->json(['error'=>'Unauthorised'], 401);
}
}
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], 200);
}
This API works on localhost but not when i open to the internet with:
php artisan serve --host 192.168.x.x --port 80
connected to a bought domain via port forwarding.
only the GET methods works, but the POST methods gives the error:
405 Method Not Allowed
As far as i could figure out, it has something to do with redirecting from http to https:
I have a same problem on a half of month ago.
The reason is when I post on valid route, it redirects from http to
https (configured by .htaccess), so "POST" method becomes "GET" and
you see a MethodNotAllowedException.
Check your browser and follow the request, you may see the accurate
problem.
from Laravel: POST method returns MethodNotAllowedHttpException
If this is the case for me as well, how do I fix the problem? The .htaccess file has nothing with https in it. Sorry if the answer is in the quoted answer but it don't know how to use that information.
UPDATE:
I found something about a csrf token problem https://laracasts.com/discuss/channels/laravel/405-method-not-allowed-laravel-55-api-passport-help. But apperently it could be fixed via entering the URIs for the POST methods in the VerifyCsrfToken file in the Middleware folder, like so:
protected $except = [
'api/register',
'api/login'
];
I still get the MethodNotAllowed error..... This is starting to really annoy as there seem to be no answers online. HELP!
Apperently i was missing the "www" when i was doing requests.
I had the following in postman:
mysite.com/api/login
but i needed:
www.mysite.com/api/login
Embarrassingly small rookie mistake that costed me 5 days to figure out... I hope this will help any new webdevelopers that run into the same issue so they don't waste time like i did.
I'd like to know is it possible to extend the built-in authentication to use an external API to authenticate a user? I'm a Laravel newbie, so I'd appreciate your help.
I'm making a custom app in Laravel 5.2 for my client, but I don't a direct access to their database server and I can only call their API to get users' details.
Thanks.
If I understood correctly you want to log users from APIs like facebook, twitter or github for example ? If that's so you need to use a laravel package named Socialite, here is the link to download and use it :
https://github.com/laravel/socialite
run on your command this :
composer require laravel/socialite
Next you need to tell laravel you want to use this package, so you need to add this in config/app.php :
'providers' => [
// Other service providers...
Laravel\Socialite\SocialiteServiceProvider::class,
],
and this is the aliases :
'Socialite' => Laravel\Socialite\Facades\Socialite::class,
Basically, you'll need to create an app on the developers site, i'll take facebook for this example.You need to go to this site :
https://developers.facebook.com/, create an account and you'll get your app url and secret key. You'll use it on your .env and config/services files.
In your config/services file add this after stripe :
'facebook' => [
'client_id' => env('FACEBOOK_ID'),
'client_secret' => env('FACEBOOK_SECRET'),
'redirect' => env('FACEBOOK_URL'),
],
And in your .env file :
FACEBOOK_ID=*your facebook id*
FACEBOOK_SECRET=*your facebook secret*
FACEBOOK_URL=http://yourwebsite.com/callback
Next you'll need a controller to handle the auth process, create something like SocialAuthController and put this in :
public function redirect()
{
return Socialite::driver('facebook')->redirect();
}
public function callback() {
$user = $this->findOrCreateFbUser(Socialite::driver('facebook')->user());
session([
'user' => $user
]);
return redirect()->route('/');
}
public function logout() {
session()->forget('user');
return redirect()->route('home');
}
protected function findOrCreateFbUser($fbUser) {
// the data you want to get from facebook
$fbData = [
'facebook_id' => $fbUser->id,
'avatar' => $fbUser->avatar,
'username' => $fbUser->name,
'email' => $fbUser->email,
];
$user = \App\User::where('facebook_id', $fbData['facebook_id'])->first();
if(!$user) $user = \App\User::create($fbData);
$user->update([
'avatar' => $fbUser->avatar,
'username' => $fbUser->name,
'email' => $fbUser->email
]);
return $user;
}
Of course you need to add a facebook_id field in your user database and model.
In User.php :
protected $fillable = [
'facebook_id',
'username',
'email',
'avatar'
];
I know this solution isn't really dynamic as it is for only one api, i'm still pretty new at Laravel too and this is my first answer to a stackoverflowquestion, but this did the trick for me :) If I forgot something don't hesitate to tell me so i can update this answer..
I also suggest you follow Jeffrey Way's tutorial on social auth on the Laracasts website, it's very instructive and clear, i could manage it thanks to him !