├── .gitattributes
├── .gitignore
├── README.md
├── composer.json
├── src
├── Helpers
│ ├── CanResetPassword.php
│ └── TokenHandler.php
├── Http
│ ├── Controllers
│ │ └── PasswordController.php
│ └── Requests
│ │ ├── RecoverPasswordRequest.php
│ │ └── ResetPasswordRequest.php
├── Jobs
│ ├── SendRecoveredPasswordJob.php
│ └── SendResetPasswordTokenJob.php
├── Mails
│ ├── PasswordRecoveredMail.php
│ └── RestPasswordTokenMail.php
├── Rules
│ └── UserExists.php
├── SimplePassportServiceProvider.php
├── Token.php
├── config
│ └── simple-passport.php
├── database
│ └── migrations
│ │ └── 2019_04_06_105400_create_simple_tokens_table.php
├── resources
│ ├── lang
│ │ └── en
│ │ │ ├── forgot-password.php
│ │ │ └── recover-password.php
│ └── views
│ │ ├── forgot-password.blade.php
│ │ └── recover-password.blade.php
└── routes
│ └── api.php
└── tests
└── GenerateTokenTest.php
/.gitattributes:
--------------------------------------------------------------------------------
1 | * text=auto
2 | *.css linguist-vendored
3 | *.scss linguist-vendored
4 | *.js linguist-vendored
5 | CHANGELOG.md export-ignore
6 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | /.idea
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
Due to a time constraint, unfortunately this repository is no longer maintained.
2 |
3 |
4 | # Installation
5 | 1/ Install Laravel passport official package, explained in the documentation [here](https://laravel.com/docs/5.8/passport#installation)
6 | Then install the simple-passport package via composer
7 |
8 | composer require heloufir/simple-passport
9 |
10 | # Configuration
11 | 1/ After installing the package, you need to publish it, by running the command:
12 |
13 | To do it, simply execute the following command
14 |
15 | php artisan vendor:publish --provider=Heloufir\SimplePassport\SimplePassportServiceProvider
16 |
17 | Or follow the steps below:
18 |
19 | php artisan vendor:publish
20 |
21 | You will be asked to choose what **tag** you want to publish (see the image below)
22 |
23 | 
24 |
25 | Next you just need to choose the tag number to publish and tap **Enter**.
26 |
27 | > For my case I choosed **3** then **Enter**
28 |
29 | 
30 |
31 | This is the message you need to see if everything is OK.
32 |
33 | 2/ Now you need to configure the **laravel/passport** package, do it by following the below steps:
34 |
35 | Execute the migration command:
36 |
37 | php artisan migrate
38 |
39 | This will show you the following message:
40 |
41 | Migrating: 2019_04_06_105400_create_simple_tokens_table
42 | Migrated: 2019_04_06_105400_create_simple_tokens_table
43 |
44 | After running this command, add the **Heloufir\SimplePassport\Helpers\CanResetPassword** trait to your **YOUR_NAMESPACE\User** model. This trait will provide a few helper methods:
45 |
46 | ```php
47 | You can override two methods **getEmailField** and **getPasswordField** for providing the names of the fields
63 |
64 | 3/ A configuration file **config/simple-passport.php** will be published. its containing the information such as the user model and more things.
65 | ```php
66 | return [
67 |
68 | /*
69 | |--------------------------------------------------------------------------
70 | | Recover url
71 | |--------------------------------------------------------------------------
72 | |
73 | | This value is the recover password url, where the user will be redirected
74 | | after he clicked on the forgot password email button.
75 | | >> To customize this value please set a new variable into the application
76 | | .env file with the following name: "SP_RECOVER_URL"
77 | |
78 | */
79 | 'recover_url' => env('SP_RECOVER_URL', 'http://localhost:4200/auth/recover/'),
80 |
81 | /*
82 | |--------------------------------------------------------------------------
83 | | Mail sender
84 | |--------------------------------------------------------------------------
85 | |
86 | | This value is the address of the sender, which be displayed in the mail
87 | | sent to the user after he request to recover his password or after his
88 | | password is recovered
89 | | >> To customize this value please set a new variable into the application
90 | | .env file with the following name: "SP_MAIL_FROM"
91 | |
92 | */
93 | 'mail_from' => env('SP_MAIL_FROM', 'noreply@application.com'),
94 |
95 | /*
96 | |--------------------------------------------------------------------------
97 | | Recover url
98 | |--------------------------------------------------------------------------
99 | |
100 | | This value is the name of the send, which be displayed in the mail
101 | | sent to the user after he request to recover his password or after his
102 | | password is recovered
103 | | >> To customize this value please set a new variable into the application
104 | | .env file with the following name: "SP_MAIL_FROM_NAME"
105 | |
106 | */
107 | 'mail_from_name' => env('SP_MAIL_FROM_NAME', 'Application'),
108 |
109 | /*
110 | |--------------------------------------------------------------------------
111 | | model
112 | |--------------------------------------------------------------------------
113 | |
114 | | The model that can use simple-passport features
115 | |
116 | */
117 |
118 | 'model' => \App\User::class,
119 |
120 | /*
121 | |--------------------------------------------------------------------------
122 | | after_seconds
123 | |--------------------------------------------------------------------------
124 | |
125 | | How many seconds before dispatch the jobs to send mails
126 | |
127 | */
128 |
129 | 'after_seconds' => 10,
130 | ];
131 |
132 | ```
133 |
134 |
135 | It's done for the **laravel/passport** configuration, the rest of the configuration is done in the **heloufir/simple-passport** side.
136 |
137 | > So from here you are ready to use **laravel/passport** and **heloufir/simple-passport** packages.
138 |
139 | # Usage
140 | ## Generate token
141 | 1/ You can generate a token for an existing user via a POST HTTP request to http://localhost/oauth/forgot-password containing an **email** field.
142 |
143 | 2/ You can recover the password for an existing user via a PUT HTTP request to http://localhost/oauth/recover-password/some-random-token containing an **email** and new **password** field.
144 |
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "heloufir/simple-passport",
3 | "description": "Simple passport, is a complete implementation of laravel/passport package, containing authentication, forgot password, recovery password, ... and all what you need to start your application that needs a complete authentication system",
4 | "type": "package",
5 | "require": {
6 | "laravel/passport": "^7.2"
7 | },
8 | "require-dev": {
9 | "fzaninotto/faker": "~1.4",
10 | "phpunit/phpunit": "~4.0"
11 | },
12 | "license": "MIT",
13 | "authors": [
14 | {
15 | "name": "EL OUFIR Hatim",
16 | "email": "eloufirhatim@gmail.com"
17 | }
18 | ],
19 | "extra": {
20 | "laravel": {
21 | "providers": [
22 | "Heloufir\\SimplePassport\\SimplePassportServiceProvider"
23 | ]
24 | }
25 | },
26 | "autoload": {
27 | "psr-4": {
28 | "Heloufir\\SimplePassport\\": "src/"
29 | }
30 | },
31 | "minimum-stability": "dev"
32 | }
33 |
--------------------------------------------------------------------------------
/src/Helpers/CanResetPassword.php:
--------------------------------------------------------------------------------
1 | hasOne(Token::class);
21 | }
22 |
23 | /**
24 | * Get the email field
25 | *
26 | * @return string
27 | */
28 | protected static function getEmailField(): string
29 | {
30 | return 'email';
31 | }
32 |
33 |
34 | /**
35 | * Get the password field
36 | *
37 | * @return string
38 | */
39 | protected function getPasswordField(): string
40 | {
41 | return 'password';
42 | }
43 |
44 | /**
45 | * Get the generated token
46 | *
47 | * @return mixed
48 | */
49 | public function getResetPasswordToken()
50 | {
51 | return $this->simpleTokens->token;
52 | }
53 |
54 | /**
55 | * Set the new password
56 | *
57 | * @param $password
58 | * @return $this
59 | */
60 | public function setNewPassword($password)
61 | {
62 | $this->{$this->getPasswordField()} = bcrypt($password);
63 |
64 | $this->save();
65 |
66 | return $this;
67 | }
68 |
69 | /**
70 | * Delete the token after setting up the new password
71 | *
72 | */
73 | public function forgotToken()
74 | {
75 | $this->simpleTokens()->delete();
76 | }
77 |
78 | /**
79 | * Token Handler
80 | *
81 | * @param $token
82 | * @return TokenHandler
83 | */
84 | public function simpleToken($token = null)
85 | {
86 | Token::where('user_id', $this->id)->delete();
87 | if(is_null($token)){
88 | return new TokenHandler(Str::random(40), $this);
89 | }
90 |
91 | return new TokenHandler($token, $this);
92 | }
93 | }
94 |
--------------------------------------------------------------------------------
/src/Helpers/TokenHandler.php:
--------------------------------------------------------------------------------
1 | token = $token;
19 | $this->user = $user;
20 | }
21 |
22 | /**
23 | * Check if the token belongs to the user
24 | *
25 | * @return bool
26 | */
27 | public function belongs()
28 | {
29 | return optional($this->user->simpleTokens)->token === $this->token;
30 | }
31 |
32 | /**
33 | * Generate the password token
34 | *
35 | * @return mixed
36 | */
37 | public function generateResetPassword()
38 | {
39 | return $this->user->simpleTokens()->save(
40 | new Token([
41 | 'token' => $this->token
42 | ])
43 | );
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/src/Http/Controllers/PasswordController.php:
--------------------------------------------------------------------------------
1 | getRelatedUser($request);
24 | $user->simpleToken()->generateResetPassword();
25 | $this->dispatchJobWithDelay(
26 | SendResetPasswordTokenJob::class, $user
27 | );
28 | return response()->json(['mail_sent' => true, 'errors' => []], 200);
29 | }
30 |
31 | /**
32 | * Recover the password
33 | *
34 | * @param RecoverPasswordRequest $request
35 | * @param string $token
36 | * @return JsonResponse
37 | */
38 | public function recover(RecoverPasswordRequest $request, string $token): JsonResponse
39 | {
40 | $user = $this->getRelatedUser($request);
41 | Log::alert($user->simpleTokens);
42 | if ($user->simpleTokens == null || $user->simpleTokens->token != $token) {
43 | return response()->json([
44 | 'password_recovered' => false,
45 | 'error' => 'Token incorrect'
46 | ], 401);
47 | }
48 | $user->setNewPassword($request->get('password'))
49 | ->forgotToken();
50 | $this->dispatchJobWithDelay(
51 | SendRecoveredPasswordJob::class, $user
52 | );
53 | return response()->json(['password_recovered' => true, 'errors' => []], 200);
54 | }
55 |
56 |
57 | /**
58 | * Get the related user
59 | *
60 | * @param $request
61 | * @return mixed
62 | */
63 | protected function getRelatedUser($request)
64 | {
65 | return $request->user_asked;
66 | }
67 |
68 | /**
69 | * @param $class
70 | * @param $user
71 | * @return mixed
72 | */
73 | protected function dispatchJobWithDelay($class, $user)
74 | {
75 | return $class::dispatch(
76 | $user
77 | )->delay(
78 | now()->addSecond(config('simple-passport.after_seconds'))
79 | );
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/src/Http/Requests/RecoverPasswordRequest.php:
--------------------------------------------------------------------------------
1 | ['required', new UserExists],
29 | 'password' => 'required|confirmed'
30 | ];
31 | }
32 |
33 | /**
34 | * Validation of the the request and attach user to it
35 | *
36 | */
37 | public function validateResolved()
38 | {
39 | parent::validateResolved();
40 |
41 | $class = config('simple-passport.model');
42 | $model = app($class);
43 | request()->request->add([
44 | 'user_asked' => $class::where($model::getEmailField(), '=', $this->request->get('email'))->first()
45 | ]);
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/src/Http/Requests/ResetPasswordRequest.php:
--------------------------------------------------------------------------------
1 | ['required', new UserExists]
29 | ];
30 | }
31 |
32 | /**
33 | * Validation of the the request and attach user to it
34 | *
35 | */
36 | public function validateResolved()
37 | {
38 | parent::validateResolved();
39 |
40 | $class = config('simple-passport.model');
41 | $model = app($class);
42 | request()->request->add([
43 | 'user_asked' => $class::where($model::getEmailField(), '=', $this->request->get('email'))->first()
44 | ]);
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/src/Jobs/SendRecoveredPasswordJob.php:
--------------------------------------------------------------------------------
1 | user = $user;
30 | }
31 |
32 | /**
33 | * Execute the job.
34 | *
35 | * @return void
36 | */
37 | public function handle()
38 | {
39 | Mail::to($this->user)->send(
40 | new PasswordRecoveredMail($this->user)
41 | );
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/src/Jobs/SendResetPasswordTokenJob.php:
--------------------------------------------------------------------------------
1 | user = $user;
30 | }
31 |
32 | /**
33 | * Execute the job.
34 | *
35 | * @return void
36 | */
37 | public function handle()
38 | {
39 | Mail::to($this->user)->send(
40 | new RestPasswordTokenMail($this->user)
41 | );
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/src/Mails/PasswordRecoveredMail.php:
--------------------------------------------------------------------------------
1 | user = $user;
27 | }
28 |
29 | /**
30 | * Build the message.
31 | *
32 | * @return $this
33 | */
34 | public function build()
35 | {
36 | return $this->view('simple-passport.recover-password')
37 | ->with(['user' => $this->user])
38 | ->from(config('simple-passport.mail_from'), config('simple-passport.mail_from_name'))
39 | ->subject(trans('simple-passport::recover-password.mail_subject'));
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/src/Mails/RestPasswordTokenMail.php:
--------------------------------------------------------------------------------
1 | user = $user;
27 | }
28 |
29 | /**
30 | * Build the message.
31 | *
32 | * @return $this
33 | */
34 | public function build()
35 | {
36 | return $this->view('simple-passport.forgot-password')
37 | ->with(['user' => $this->user, 'token' => $this->user->simpleTokens->token])
38 | ->from(config('simple-passport.mail_from'), config('simple-passport.mail_from_name'))
39 | ->subject(trans('simple-passport::forgot-password.mail_subject'));
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/src/Rules/UserExists.php:
--------------------------------------------------------------------------------
1 | model = app(config('auth.providers.users.model'));
14 | }
15 |
16 | /**
17 | * Determine if the validation rule passes.
18 | *
19 | * @param string $attribute
20 | * @param mixed $value
21 | * @return bool
22 | */
23 | public function passes($attribute, $value)
24 | {
25 | return $this->model->where(($this->model->simplePassport ?: 'email'), '=', $value)->count() !== 0;
26 | }
27 |
28 | /**
29 | * Get the validation error message.
30 | *
31 | * @return string
32 | */
33 | public function message()
34 | {
35 | return trans('validation.exists', ['attribute' => 'user']);
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/src/SimplePassportServiceProvider.php:
--------------------------------------------------------------------------------
1 | app->make(PasswordController::class);
20 | }
21 |
22 | /**
23 | * Bootstrap services.
24 | *
25 | * @return void
26 | */
27 | public function boot()
28 | {
29 | // Register laravel/passport routes
30 | Passport::routes();
31 |
32 | // Register package routes
33 | $this->loadRoutesFrom(__DIR__ . '/routes/api.php');
34 |
35 | // Register package migrations
36 | $this->loadMigrationsFrom(__DIR__ . '/database/migrations');
37 |
38 | // Register package views
39 | $this->loadViewsFrom(__DIR__.'/resources/views', 'simple-passport');
40 |
41 | // Register package translations
42 | $this->loadTranslationsFrom(__DIR__.'/resources/lang', 'simple-passport');
43 |
44 | // Publish package sources
45 | $this->publishes([
46 | __DIR__.'/resources/views' => resource_path('views/simple-passport'),
47 | __DIR__.'/config/simple-passport.php' => config_path('simple-passport.php'),
48 | __DIR__.'/resources/lang' => resource_path('lang/vendor/simple-passport')
49 | ]);
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/src/Token.php:
--------------------------------------------------------------------------------
1 | > To customize this value please set a new variable into the application
13 | | .env file with the following name: "SP_RECOVER_URL"
14 | |
15 | */
16 | 'recover_url' => env('SP_RECOVER_URL', 'http://localhost:4200/auth/recover/'),
17 |
18 | /*
19 | |--------------------------------------------------------------------------
20 | | Mail sender
21 | |--------------------------------------------------------------------------
22 | |
23 | | This value is the address of the sender, which be displayed in the mail
24 | | sent to the user after he request to recover his password or after his
25 | | password is recovered
26 | | >> To customize this value please set a new variable into the application
27 | | .env file with the following name: "SP_MAIL_FROM"
28 | |
29 | */
30 | 'mail_from' => env('SP_MAIL_FROM', 'noreply@application.com'),
31 |
32 | /*
33 | |--------------------------------------------------------------------------
34 | | Recover url
35 | |--------------------------------------------------------------------------
36 | |
37 | | This value is the name of the send, which be displayed in the mail
38 | | sent to the user after he request to recover his password or after his
39 | | password is recovered
40 | | >> To customize this value please set a new variable into the application
41 | | .env file with the following name: "SP_MAIL_FROM_NAME"
42 | |
43 | */
44 | 'mail_from_name' => env('SP_MAIL_FROM_NAME', 'Application'),
45 |
46 | /*
47 | |--------------------------------------------------------------------------
48 | | model
49 | |--------------------------------------------------------------------------
50 | |
51 | | The model that can use simple-passport features
52 | |
53 | */
54 |
55 | 'model' => \App\User::class,
56 |
57 | /*
58 | |--------------------------------------------------------------------------
59 | | after_seconds
60 | |--------------------------------------------------------------------------
61 | |
62 | | How many seconds before dispatch the jobs to send mails
63 | |
64 | */
65 |
66 | 'after_seconds' => 10,
67 | ];
68 |
--------------------------------------------------------------------------------
/src/database/migrations/2019_04_06_105400_create_simple_tokens_table.php:
--------------------------------------------------------------------------------
1 | increments('id');
18 | $table->integer('user_id');
19 | $table->string('token');
20 | $table->string('expires_at')->nullable();
21 | $table->timestamps();
22 | });
23 | }
24 |
25 | /**
26 | * Reverse the migrations.
27 | *
28 | * @return void
29 | */
30 | public function down()
31 | {
32 | Schema::dropIfExists('simple_tokens');
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/src/resources/lang/en/forgot-password.php:
--------------------------------------------------------------------------------
1 | 'Forgot your password?',
5 | 'title' => 'Forgot your password?',
6 | 'notification_description' => 'Forgot your password? No worries, take a moment and follow the steps described in this email to recover your password.',
7 | 'description' => 'No worries! Take a moment and follow the steps described in this email to recover your password'
8 | . '
First of all click on the following button:',
9 | 'button' => 'Recover your password'
10 | ];
--------------------------------------------------------------------------------
/src/resources/lang/en/recover-password.php:
--------------------------------------------------------------------------------
1 | 'Password recovered',
5 | 'title' => 'Password recovered',
6 | 'notification_description' => 'Congrats! Your password was successfully recovered. You can now log on using your new password.',
7 | 'description' => 'Congrats! Your password was successfully recovered. You can now log on using your new password.'
8 | ];
--------------------------------------------------------------------------------
/src/resources/views/forgot-password.blade.php:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | @lang('simple-passport::forgot-password.title')
9 |
10 |
11 |
12 |
13 |
14 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
130 |
131 |
132 |
140 |
141 |
142 |
143 |
144 |
197 |
198 |
199 |
200 |
206 |
207 |
208 |
213 |
214 |
215 |
216 | @lang('simple-passport::forgot-password.notification_description')
217 |
218 |
219 |
220 |
221 |
222 |
223 |
224 |
225 |
226 |
227 |
228 |
229 |
230 |
231 |
232 |
233 |
234 | |
235 |
236 |
237 |
238 |
239 |
240 |
241 |
242 |
243 |
244 | @lang('simple-passport::forgot-password.title')
245 | @lang('simple-passport::forgot-password.description')
246 | |
247 |
248 |
249 |
250 |
251 |
258 |
259 | |
260 |
261 |
262 |
263 | |
264 |
265 |
266 |
267 |
268 |
269 |
270 |
275 |
276 |
277 |
278 |
--------------------------------------------------------------------------------
/src/resources/views/recover-password.blade.php:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | @lang('simple-passport::recover-password.title')
9 |
10 |
11 |
12 |
13 |
14 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
130 |
131 |
132 |
140 |
141 |
142 |
143 |
144 |
197 |
198 |
199 |
200 |
206 |
207 |
208 |
213 |
214 |
215 |
216 | @lang('simple-passport::recover-password.notification_description')
217 |
218 |
219 |
220 |
221 |
222 |
223 |
224 |
225 |
226 |
227 |
228 |
229 |
230 |
231 |
232 |
233 |
234 | |
235 |
236 |
237 |
238 |
239 |
240 |
241 |
242 |
243 |
244 | @lang('simple-passport::recover-password.title')
245 | @lang('simple-passport::recover-password.description')
246 | |
247 |
248 |
249 |
250 | |
251 |
252 |
253 |
254 |
255 |
256 |
257 |
262 |
263 |
264 |
265 |
--------------------------------------------------------------------------------
/src/routes/api.php:
--------------------------------------------------------------------------------
1 | name('simple-passport.password.forgot');
5 |
6 | Route::put('oauth/recover-password/{token}', 'Heloufir\SimplePassport\Http\Controllers\PasswordController@recover')
7 | ->name('simple-passport.password.recover');
--------------------------------------------------------------------------------
/tests/GenerateTokenTest.php:
--------------------------------------------------------------------------------
1 |