I have an api that has a method to start and I am calling it from a frontend project.
In the front end project I use Guzzle to make the call via post to the api and login, from which I get back a json with the user data and a jwt token.
But when I receive the token as I manage the session, I must create a session and save the token, since the laravel to authenticate I need a model user and have a database, which of course I do not have in this backend because I call the api to log in, which brings a token and user data, then as I manage it from the backend, I'm a little lost there.
$api = new Api();
$response = $api->loginapi(['user'=>'wings#test.com','password'=>'123']);
Because here I could not do Auth::login($user) to generate the session.
Because I don't have here the database because the login is done from the api.
There I call the api, of which the answer is the token, but how do I manage it from here, creating a session? saving the token?
thanks for your help.
With api, you don't usually manage a session. usually, you'd call something like
Auth::attempt([
'email' => 'me#example.com',
'password' => 'myPassword'
]);
If the credentials are correct, laravel will include a Set-Cookie header in response, and, that is how you authenticate with api. Via an auth cookie. You don't need to do anything else.
Let's show you how:
//AuthController.php
public function login(Request $request) {
$validatedData = $request->validate([
'email' => 'required|email',
'password' => 'required'
]);
if(Auth::attempt($validatedData)){
return ['success' => 'true'];
}
else{
return ['success' => false, 'message' => 'Email or password Invalid'];
}
}
public function currentUser (){
return Auth::user();
}
Now, the APi file
Route::post('/login', ['App\Http\Controllers\AuthController', 'login']);
Route::get('/current_user', ['App\Http\Controllers\AuthController', 'currentUser']);
Now if you make a call to /api/current_user initially, you'll get null response since you're not currently logged in. But once you make request to /api/login and you get a successful response, you are now logged in. Now if you go to /api/current_user, you should see that you're already logged in.
Important ::
If you are using fetch, you need to include credentials if you're using something other than fetch, check out how to use credentials with that library or api
You want to use the API to authenticate and then use the SessionGuard to create session including the remember_me handling.
This is the default login controller endpoint for logging in. You don't want to change this, as it makes sure that user's do not have endless login attempts (protects for brut-force attacks) and redirects to your current location.
public function login(Request $request)
{
$this->validateLogin($request);
// If the class is using the ThrottlesLogins trait, we can automatically throttle
// the login attempts for this application. We'll key this by the username and
// the IP address of the client making these requests into this application.
if (method_exists($this, 'hasTooManyLoginAttempts') &&
$this->hasTooManyLoginAttempts($request)) {
$this->fireLockoutEvent($request);
return $this->sendLockoutResponse($request);
}
if ($this->attemptLogin($request)) {
if ($request->hasSession()) {
$request->session()->put('auth.password_confirmed_at', time());
}
return $this->sendLoginResponse($request);
}
// If the login attempt was unsuccessful we will increment the number of attempts
// to login and redirect the user back to the login form. Of course, when this
// user surpasses their maximum number of attempts they will get locked out.
$this->incrementLoginAttempts($request);
return $this->sendFailedLoginResponse($request);
}
The core happens when we try to "attemptLogin" at
protected function attemptLogin(Request $request)
{
return $this->guard()->attempt(
$this->credentials($request), $request->boolean('remember')
);
}
When using the SessioGurad (which is default) the method attemptLogin fires a couple of events, checks if the user has valid credentials (by hashing the password and matching it with db) and then logs the user in, including the remember me functionality.
Now, if you don't care about events, you can just check from your API if the credentials match and then use the login method from the guard. This will also handle the remember me functionality. Something like this:
protected function attemptLogin(Request $request)
{
$username = $request->input($this->username());
$password = $request->input('password');
$result = \Illuminate\Support\Facades\Http::post(env('YOUR_API_DOMAIN') . '/api/v0/login' , [
'username' => $username,
'password' => $password
])->json();
if(empty($result['success'])){
return false;
}
// Maybe you need to create the user here if the login is for the first time?
$user = User::where('username', '=', $username)->first();
$this->guard()->login(
$user, $request->boolean('remember')
);
return true;
}
I'm trying to setup login in Laravel with GitHub using Socialite.
Here is my provider callback function:
public function handleProviderCallback($provider)
{
$provider_user = Socialite::driver($provider)->user();
dd($provider_user);
if($provider_user->email) {
$user = User::firstOrCreate([
'email' => $provider_user->email
], [
'name' => $provider_user->name ?? $provider_user->nickname,
'password' => Hash::make(Str::random(16)),
]);
Auth::login($user, true);
}
return redirect('/');
}
When I dd the user that provider returns, I can see that values $provider_user->name and $provider_user->nickname are correct, but $provider_user->email is null.
Which, according to the GitHub API documentation shouldn't be the case, as my e-mail is public:
I have tried https://api.github.com/user/emails where I've tried putting user nickname, as well as client ID in place of user, but to no avail. The response is:
{ "message": "Not Found", "documentation_url": "https://docs.github.com/rest" }
So, am I doing something wrong or GitHub API simply no longer returns e-mail addresses? Is there a way to get a public e-mail address?
I was having the same problem earlier.
What I did upon creating the github app is change the User permissions->Email addresses to read only. You can update it on the permission & events:
I need to validate extra fields in my users table before i create the requested tokens, but i can't find a simple way to do it with Passport.
I find similar workarunds which returns a token using $user->createToken() but i can't find someone covering all default /oauth/token options like the refresh_token
Also i see Passport have some simple ways to customize the username column and the password validation but i think this not cover my neededs.
Update
Im not sure if this is the best solution but in Laravel 5.8 the passport package have this validateForPassportPasswordGrant() function which allow you to add some extra conditionals before allowing the authentication process to get completed.
class User extends Authenticatable
{
public function validateForPassportPasswordGrant($password)
{
if ($this->active != true) {
throw OAuthServerException::accessDenied('The account is not active');
}
return Hash::check($password, $this->password);
}
}
In your login method
if (Auth::attempt(['email' => $request->email, 'password' => $request->password, 'is_active' => 1, 'username' => $request->username])) {
// create a token here
}
I am doing some POSTing to my laravel API.
I have added a unique 'api_token' column to the users table, and I want to retrieve the user from this token.
In a controller I can validate a token - the $apiUserValid is true or false depending on whether or not a row exists with a matching api_token value:
$apiToken = "Y2uibY5MIV";//correct token
$apiCredentials = ['api_token' => $apiToken];
$apiUserValid = \Auth::guard('api')->validate($apiCredentials);
if ($apiUserValid) {
var_dump(\Illuminate\Support\Facades\Auth::user()); // shows "NULL"
var_dump(\Illuminate\Support\Facades\Auth::id()); //shows NULL
var_dump(\Illuminate\Support\Facades\Auth::guard('api')->user()); // shows "NULL"
die();
} else {
die('not valid');// when the token is incorrect this branch is taken
}
However, I want to get the userId of the user with that token.
The SessionGuard has some methods that look relevant - such as login() but these are not present in the TokenGuard.
I am currently simulating this in a controller rather than dealing with a http request object - this could be part of my problem.
How do I get the user id of the person making the POST?
You can use this:
<?php
use Illuminate\Support\Facades\Auth;
$userId = Auth::id();
The relevant documentation is here.
Alternatively, you can use this:
<?php
use App\User;
$user = User::where('api_token', $apiToken)->first();
$userId = $user->id;
Due to laravel's default auth system not working for my current project I used their manual authentication system. The authenticating works but after I redirect the authentication gets destroyed or it simply isn't getting stored properly.
My authController:
use Illuminate\Routing\Controller;
use Illuminate\Support\Facades\Auth;
class manualAuthController extends Controller {
public function authenticate(){
if (Auth::attempt(['email' => $_POST['email'], 'password' => $_POST['password']])) {
// Authentication passed...
$user = Auth::user();
//return '$user';
return redirect("test2");
}
return 'Auth failed!';
}
}
My route to test if the authenticated user is still stored:
Route::get('test2', function(){
echo 'test2<br>';
$user = Auth::user();
echo $user;
return '.';
});
If I uncomment "return '$user';" then the authenticated user gets returned properly.
I know that this question has been asked before but I couldn't find anybody with a working/ reliable solution to this problem so can someone here please help me with this problem(or finding the exact problem)?
Side note: I previously used the Socialite system which we had to switch for the laravel auth due to hosting problems. After this switch it worked in development for a while with my current session and db settings. Due to some other bugs I switched to manual authentication.