I'm trying to modify the default Laravel 5.6 Auth in a way to email new users a link to create their password, since this is an invite only system and I don't want to email created users their password as plaintext.
In 5.3 what I was able to do was grab the reset token from the password_resets table and send them a Notification with a "Create Password" button.
In 5.6 (not sure when this changed) it seems to be an encrypted version of their password reset token in the database. How would I then call the correct url in a custom notification for users to be able to create a password?
Here's what I had in 5.3:
controller
......
$token = strtolower(str_random(64));
DB::table('password_resets')->insert([
'email' => $request->email,
'token' => $token,
'created_at' => Carbon::now()
]);
$user->notify(new UserCreated($user));
......
password create email
.....
$token = DB::table('password_resets')->where('email', $user_email)->pluck('token')->first();
$url = url('/password/reset/' . $token);
......
Copying the same code over to 5.6, it tells me my reset tokens are invalid. It appears the tokens in the database no longer match the token in the url when doing a normal password reset. Now they appear to be encrypted or something?
I've made sure in the email the url and the token match exactly whats in the database, with the valid period set to like a week (to test), and every token created this way it says is invalid.
How then do you do auth for an invite only system, or how do you just manually create a reset token and then send it in a custom email? The docs mentions being able to replace the password reset email, but I don't want that, I want to supplement it.
Creating and saving the token can be done in a single line using the built-in functionality. Took me an hour and prodigious use of dd() to figure it out, but I added this to my User model:
<?php
namespace App;
use App\Notifications\AccountCreated;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Illuminate\Support\Facades\Hash;
class User extends Authenticatable
{
use Notifiable;
public function generatePassword()
{
$this->password = Hash::make(str_random(32));
}
public function sendWelcomeEmail()
{
// Generate a new reset password token and save it to the database
$token = app("Password")::getRepository()->create($this);
// Send notification
$this->notify(new AccountCreated($this, $token));
}
}
The notification gets the user and the token, same as your code, so that they can be included in the email text. Then in UserController::store() I can just do:
$user = new User($request->all());
$user->generatePassword();
$user->save();
$user->sendWelcomeEmail();
In the email notification, you can use this to get the actual URL:
$url = route("password.reset", $token)
Solved it!
Here's my new controller and notification in 5.6 for manually sending a different password create email. All I really had to do was encrypt the token before storing it in the database! Then you pass the unencrypted token to the email for the url, which checks against the encrypted one in the DB.
controller
.....
$random_token = strtolower(str_random(60));
$encrypted_token = bcrypt($random_token);
DB::table('password_resets')->insert([
'email' => $request->email,
'token' => $encrypted_token,
'created_at' => Carbon::now()
]);
$user->notify(new AccountCreated($user, $random_token));
.....
In the email I'm just importing the user and the token...
.....
public $user;
public $token;
public function __construct(User $user, $token)
{
$this->user = $user;
$this->token = $token;
}
.....
Related
I am using passport package in my project. Everything is working fine. I need custom functionality in which I can login through provider_id instead of email and password.
The below code is working absolutely fine
$credentials = request(['email', 'password']);
if(!Auth::attempt($credentials))
return response()->json([
'status' => 'fail',
'message' => 'The given data was invalid.'
], 401);
$user = $request->user();
$tokenResult = $user->createToken('Personal Access Token');
$token = $tokenResult->token;
if ($request->remember_me)
$token->expires_at = Carbon::now()->addWeeks(1);
$token->save();
I want to have same functionality as like below
Auth::attempt($credentials)
But through provider_id, and I can use these input for login which are in same `users
name
provider
provider_id
can someone kindly guide me about that I would appreciate. Thank you.
Authenticate A User By ID
To log a user into the application by their ID, you may use the loginUsingId method. This method accepts the primary key of the user you wish to authenticate:
Auth::loginUsingId(1);
// Login and "remember" the given user...
Auth::loginUsingId(1, true);
Reference
You can make some changes in the same method or you can create your own custom login method as per your requirement.
I am a newbie to JWT Token System in laravel 5 and using tymon JWT Auth
I managed to create my custom JWT token and my code as follows
use App\Http\Requests;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Tymon\JWTAuth\JWTManager as JWT;
use JWTAuth;
use JWTFactory;
use Tymon\JWTAuth\Exceptions\JWTException;
public function login(Request $request)
{
$customClaims = ['foo' => 'bar', 'baz' => 'bob'];
$payload = JWTFactory::make($customClaims);
$token = JWTAuth::encode($payload);
// return response()->json(compact('token')); // This didnt work?Why?
return response()->json(compact($token))->header('Authorization','Bearer '.$token);
}
public function getUser(){
$token = JWTAuth::parseToken();
echo $token;
}
Here are my following clarifications required
// return response()->json(compact('token'));
Why this gave me an empty json object as {"token":{}}
Is it the right way, i could send my custom data in token and get it back the foo and baz values from the same token?
The output of my code while testing with postman is an empty array. as []. But my headers are added with Authorization →Bearer eyJ0eXAiOiJKV1QiLCJhbG...
Is this correct?
3a. Instead of a simple blank array, i need a success message as 'authorized':true. How can i achieve it?
How should i pass this token back to test. Where should this token be passed using postman. I passed it through Headers as shown in the image
How could i parse this token using laravel and get the custom data i.e foo and baz sent as a token. The method i called is getUser here.
I dont think the token creation is being built properly. Below is working code for login token creation. For this, make sure that the 'user' model under your config/jwt.php is the correct eloquent user model for your application.
$user = array(
'user' => $request->input('email'),
'password' => $request->input('pass')
);
$customClaims= ['usr' => $user['user']];
if(!$token = JWTAuth::attempt($user, $customClaims)){
abort(401);
}
else{
return response()->json(compact('token'));
}
Also included in the above code with the custom claims variable, you were on the right track with that just needs to be passed as a second parameter in the attempt function.
Only the client needs to send the authorization: Bearertoken header to prove that they are who they say they are (I am coming from an android client/server jwt background. So sorry if this doesnt apply to your application).
3a. For any subsequent pages that the user browses to, you simply add an if statement like this
if(!$user = JWTAuth::parseToken()->authenticate()){
abort(401);
}
else{
// Code allowing the user to see protected content
}
See answer to question 3. include an http header with authorization BearerToken
To extract the data from the JWT Payload, you will need to decode the base64 encoded text from the text after the first period in the token and send that to a string. Then run that string through the base64_decode($string) function. That should start to give you some of the payload data.
Hope this helps.
I had the same problem here and i got the following solution:
public function whatEver()
{
$token = JWTAuth::parseToken();
$response = $token->getPayload()->get('foo');
return $response
}
this should return bar.
you can use this method in your user model :
/**
* Return a key value array, containing any custom claims to be added to the JWT.
*
* #return array
*/
public function getJWTCustomClaims()
{
return [
'perms' => '
'
];
}
I'm trying to learn Laravel and my goal is to be able to build a RESTful API (no use of views or blade, only JSON results. Later, an AngularJS web app and a Cordova hybrid mobile app will consume this api.
After some research, I'm inclining to choose JWT-Auth library for completely stateless benefit. My problem is: I have 2 main types of users: customers and moderators. Customers are not required to have a password. I need to be able to generate a token for access with the provided email only. If that email exists in the database and it belongs to a customer, it will generate and return the token.
If it exists and belongs to a moderator, it will return false so the interface can request a password. If the email doesn't exist, it throws an invalid parameter error.
I read the docs here and it says it's possible to use Custom Claims. But the docs doesn't explain what are claims and what it means the array being passed as custom claims. I'd like some input on how to go about achieving what I explain above.
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Http\Requests;
use App\Http\Controllers\Controller;
use JWTAuth;
use Tymon\JWTAuth\Exceptions\JWTException;
class AuthenticateController extends Controller
{
public function authenticate(Request $request)
{
$credentials = $request->only('email', 'password');
try {
// verify the credentials and create a token for the user
if (! $token = JWTAuth::attempt($credentials)) {
return response()->json(['error' => 'invalid_credentials'], 401);
}
} catch (JWTException $e) {
// something went wrong
return response()->json(['error' => 'could_not_create_token'], 500);
}
// if no errors are encountered we can return a JWT
return response()->json(compact('token'));
}
}
Thanks you.
Update
Bounty's code
public function authenticate(Request $request) {
$email = $request->input('email');
$user = User::where('email', '=', $email)->first();
try {
// verify the credentials and create a token for the user
if (! $token = JWTAuth::fromUser($user)) {
return response()->json(['error' => 'invalid_credentials'], 401);
}
} catch (JWTException $e) {
// something went wrong
return response()->json(['error' => 'could_not_create_token'], 500);
}
// if no errors are encountered we can return a JWT
return response()->json(compact('token'));
}
try with this:
$user=User::where('email','=','user2#gmail.com')->first();
if (!$userToken=JWTAuth::fromUser($user)) {
return response()->json(['error' => 'invalid_credentials'], 401);
}
return response()->json(compact('userToken'));
it works for me, hope can help
Generating token for the customers (without password) can be achieved through
$user = \App\Modules\User\Models\UserModel::whereEmail('xyz#gmail.com')->first();
$userToken=JWTAuth::fromUser($user);
Here $userToken
will stores the token after existence check of email in the table configured in UserModel file.
I have assumed that you stores both customer and moderators in the same table, there must be some flag to discriminate among them. Assume the flag is user_type
$token = null;
$user = \App\Modules\User\Models\UserModel::whereEmail('xyz#gmail.com')->first();
if($user['user_type'] == 'customer'){
$credentials = $request->only('email');
$token =JWTAuth::fromUser($user);
}else if($user['user_type'] == 'moderator'){
$credentials = $request->only('email','password');
$token = JWTAuth::attempt($credentials);
}else{
//No such user exists
}
return $token;
As far as custom claims are concerned these are custom defined payloads which can be attached to token string.
For example, JWTAuth::attempt($credentials,['role'=>1]); Will attempt to add role object to token payload.
Once you decode the token string through JWT Facade JWTAuth::parseToken()->getPayload(); you in turn get all payloads defined in required_claims under config/jwt.php with additional role payload.
Refer https://github.com/tymondesigns/jwt-auth/wiki/Creating-Tokens#creating-a-token-based-on-anything-you-like
Let me know in case you requires anything else.
Rather than making a different login strategy for customers and moderators, you can add token authentication to both user type. this will makes your life easier and prepare for scalability.
In your api, you can just restrict moderator users to not have access to the api by sending
<?php
Response::json('error'=>'method not allowed')
Apart from this suggestion, I believe #Alimnjan code should work.
If you don't already have an App\User object, get it with something like
$user = App\User::find(1);
Generate the token using the fromUser() method of JWTAuth
$token = \JWTAuth::fromUser($user)
The above doesn't authenticate the user, it only generates a JWT token. If you need to authenticate the user, then you have to add something like this
\JWTAuth::setToken($token)->toUser();
I have asked this question already but still I didn't get an answer.
How to login using Github, Facebook, Gmail and Twitter in Laravel 5.1?
auth not working
I am able to store data from gmail, github in the database.
Controller
if (Auth::attempt(['email' => $email, 'password' => $user_id]))
{
return redirect()->intended('user/UserDashboard');
}
else
{
//here i am going to insert if user not logged in already
return redirect()->intended('user/UserDashboard');
}
My problem is if I echo any data instead of return redirect()->intended('user/UserDashboard'); then it displays. If I add redirect then it doesn't work.
I'm not entirely sure how it works when using google for oAuth, but I assume your desired flow is:
User returns from google.
Check if user already exists, otherwise create new user record.
Log user in.
Redirect to dashboard.
Assuming the above your methods would look something like this.
Controller
public function google()
{
// Redirect user to google for authentication
return Socialite::driver('google')->redirect();
// In Laravel 5.0 this would be
// return Socialize::with('google')->redirect();
}
public function googleCallback()
{
// Return from google with user object
$googleUser = Socialite::driver('google')->user();
// In Laravel 5.0 the above would be
// $user = Socialize::with('google')->user();
// If user exists, retrieve the first() record,
// otherwise create a new record
$user = User::firstOrCreate([
'user_id' => $googleUser->id,
'name' => $googleUser->name,
'password' => $googleUser->id,
'email' => $googleUser->email,
'avatar' => $googleUser->avatar
]);
// Login the user
Auth::login($user, true);
// Redirect to the dashboard
return Redirect::intended('user/UserDashboard');
}
After reading: http://laravel.com/docs/5.0/authentication I was able to retrieve the user details from the OAuth provider (Facebook) using Socialite:
$user->getNickname();
$user->getName();
$user->getEmail();
$user->getAvatar();
But I couldn't find any further documentation on how to save the user in the database or log the user in.
I want to do the equivalent to:
Auth::attempt(['email' => $email, 'password' => $password])
But for the details retrieved via Socialite (I don't have a password)
Can you please show me an example on using "Auth" with user data retrieved via Socialite?
Add to "users" table new column: facebook_user_id. Every time when user tries to login through Facebook, Facebook will return the same user id.
public function handleProviderCallback($provider)
{
$socialize_user = Socialize::with($provider)->user();
$facebook_user_id = $socialize_user->getId(); // unique facebook user id
$user = User::where('facebook_user_id', $facebook_user_id)->first();
// register (if no user)
if (!$user) {
$user = new User;
$user->facebook_id = $facebook_user_id;
$user->save();
}
// login
Auth::loginUsingId($user->id);
return redirect('/');
}
How Laravel Socialite works?
public function redirectToProvider()
{
// 1. with this method you redirect user to facebook, twitter... to get permission to use user data
return Socialize::with('github')->redirect();
}
public function handleProviderCallback()
{
// 2. facebook, twitter... redirects user here, where you write code to log in user
$user = Socialize::with('github')->user();
}