├── .gitignore
├── routes
└── api.php
├── config
└── hashed-passport.php
├── phpunit.xml.dist
├── src
├── HashedPassport.php
├── Traits
│ ├── HashesIds.php
│ └── HandlesEncryptedSecrets.php
├── Middleware
│ └── DecodeHashedClientIdOnRequest.php
├── Commands
│ ├── Install.php
│ └── Uninstall.php
├── Observers
│ └── ClientObserver.php
└── HashedPassportServiceProvider.php
├── database
└── migrations
│ └── 2018_03_30_182458_oauth_clients_secret_change_varchar_length.php
├── LICENSE.txt
├── tests
├── HashingTest.php
├── EncryptionTest.php
└── TestCase.php
├── composer.json
└── readme.md
/.gitignore:
--------------------------------------------------------------------------------
1 | /composer.lock
2 | /vendor
3 |
--------------------------------------------------------------------------------
/routes/api.php:
--------------------------------------------------------------------------------
1 | middleware(['throttle', 'hashed_passport']);
5 |
--------------------------------------------------------------------------------
/config/hashed-passport.php:
--------------------------------------------------------------------------------
1 | env('APP_KEY'),
19 |
20 | ];
21 |
--------------------------------------------------------------------------------
/phpunit.xml.dist:
--------------------------------------------------------------------------------
1 |
2 |
13 |
14 |
15 | ./tests/
16 |
17 |
18 |
19 |
20 | ./src/
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/src/HashedPassport.php:
--------------------------------------------------------------------------------
1 | encode($id);
26 | }
27 |
28 | /**
29 | * UnHashes the hashed client_id into the auto-incrementing integer
30 | *
31 | * @param $client_id
32 | *
33 | * @return mixed
34 | */
35 | protected function decode($client_id)
36 | {
37 | return Hashids::connection('hashed_passport')->decode($client_id);
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/src/Middleware/DecodeHashedClientIdOnRequest.php:
--------------------------------------------------------------------------------
1 | offsetExists('client_id')) {
21 | $client_id = $request->offsetGet('client_id');
22 |
23 | if (!is_numeric($client_id)) {
24 | $result = $this->decode($client_id);
25 |
26 | if (count($result) > 0) {
27 | $request->offsetSet('client_id', $result[0]);
28 | } else {
29 | $request->offsetSet('client_id', -1);
30 | }
31 | }
32 | }
33 |
34 | return $next($request);
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/database/migrations/2018_03_30_182458_oauth_clients_secret_change_varchar_length.php:
--------------------------------------------------------------------------------
1 | string('secret', 2048)->change();
21 | });
22 | }
23 |
24 | /**
25 | * Reverse the migrations.
26 | *
27 | * @return void
28 | */
29 | public function down()
30 | {
31 | /**
32 | * Change the value back to it's default value of 100
33 | */
34 | Schema::table('oauth_clients', function (Blueprint $table) {
35 | $table->string('secret', 100)->change();
36 | });
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/LICENSE.txt:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c)
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in
13 | all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | THE SOFTWARE.
--------------------------------------------------------------------------------
/tests/HashingTest.php:
--------------------------------------------------------------------------------
1 | client = $this->createTestClient();
19 | }
20 |
21 | /** @test */
22 | public function adds_client_id_to_model_when_loading()
23 | {
24 | // Given
25 | // When
26 | // Then
27 | $this->assertArrayHasKey('client_id', $this->client->toArray());
28 | }
29 |
30 | /** @test */
31 | public function hashes_client_id()
32 | {
33 | // Given
34 | $database_client = DB::table($this->client->getTable())->where('id', '=', $this->client->id)->first();
35 |
36 | // When
37 | $this->assertNotEquals($database_client->id, $this->client->client_id);
38 |
39 | // And when decoded, they're the same
40 | $this->assertEquals($database_client->id, $this->decode($this->client->client_id)[0]);
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/src/Commands/Install.php:
--------------------------------------------------------------------------------
1 | encrypt_client_secrets();
44 | $this->secrets_encrypted();
45 | }
46 |
47 | $this->info('Hashed Passport installation completed.');
48 | $this->info('');
49 | $this->info('');
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/src/Commands/Uninstall.php:
--------------------------------------------------------------------------------
1 | decrypt_client_secrets();
44 | $this->secrets_decrypted();
45 | }
46 |
47 | $this->info('Hashed-passport removal completed.');
48 | $this->info('');
49 | $this->info('You can now safely run:');
50 | $this->info('composer remove ssmulders/hashed-passport');
51 | $this->info('');
52 | $this->info('');
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "ssmulders/hashed-passport",
3 | "description": "Transforms Laravel Passport's default incrementing integer client_id into an industry standard unique hashed string. Optionally, you can use encrypted client secrets for improved security. The package is non-intrusive. See the readme for details.",
4 | "type": "library",
5 | "license": "MIT",
6 | "support": {
7 | "issues": "https://github.com/ssmulders/hashed-passport/issues",
8 | "source": "https://github.com/ssmulders/hashed-passport"
9 | },
10 | "authors": [
11 | {
12 | "name": "Stan Smulders",
13 | "email": "stansmulders@gmail.com"
14 | }
15 | ],
16 | "require": {
17 | "laravel/passport": "^7.0",
18 | "vinkla/hashids": ">=5.0 <8.0",
19 | "doctrine/dbal": "^2.6"
20 | },
21 | "require-dev": {
22 | "mockery/mockery": "~1.0",
23 | "orchestra/testbench": "~3.7",
24 | "phpunit/phpunit": ">=7.5 <9.0"
25 | },
26 | "autoload": {
27 | "psr-4": {
28 | "Ssmulders\\HashedPassport\\": "src/"
29 | }
30 | },
31 | "autoload-dev": {
32 | "psr-4": {
33 | "Ssmulders\\HashedPassport\\Tests\\": "tests/"
34 | }
35 | },
36 | "extra": {
37 | "branch-alias": {
38 | "dev-master": "1.1-dev"
39 | },
40 | "laravel": {
41 | "providers": [
42 | "Ssmulders\\HashedPassport\\HashedPassportServiceProvider"
43 | ]
44 | }
45 | },
46 | "config": {
47 | "sort-packages": true
48 | },
49 | "minimum-stability": "dev",
50 | "prefer-stable": true
51 | }
52 |
--------------------------------------------------------------------------------
/src/Observers/ClientObserver.php:
--------------------------------------------------------------------------------
1 | setAttribute('client_id', $this->encode($oauth_client->getAttribute('id')));
25 | $oauth_client->setAttribute('client_id', $this->encode($oauth_client->getAttribute('id')));
26 |
27 | if (HashedPassport::$withEncryption) {
28 | $oauth_client->setAttribute('secret', decrypt($oauth_client->getAttribute('secret')));
29 | }
30 | }
31 |
32 | /**
33 | * Encrypt the Client Secret before storing it.
34 | *
35 | * @param Client $oauth_client
36 | */
37 | public function saving(Client $oauth_client)
38 | {
39 | // Prevent trying to save hashed client ID to the database.
40 | $oauth_client->offsetUnset('client_id');
41 |
42 | if (HashedPassport::$withEncryption) {
43 | $oauth_client->setAttribute('secret', encrypt($oauth_client->getAttribute('secret')));
44 | }
45 | }
46 |
47 | /**
48 | * Hash the Client ID and encrypt secret after saving.
49 | *
50 | * @param Client $oauth_client
51 | */
52 | public function saved(Client $oauth_client)
53 | {
54 | $this->retrieved($oauth_client);
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/tests/EncryptionTest.php:
--------------------------------------------------------------------------------
1 | client = $this->createTestClient();
22 | }
23 |
24 | /** @test */
25 | public function database_secret_is_stored_encrypted()
26 | {
27 | // Given
28 | $database_client = DB::table($this->client->getTable())->where('id', '=', $this->client->id)->first();
29 |
30 | $application_secret = $this->client->secret;
31 | $database_secret = $database_client->secret;
32 |
33 | // Checks with and without encryption
34 | // When disabled in AppServiceProvider it uses the else clause.
35 | if (HashedPassport::$withEncryption) {
36 | // Make sure that what's stored in the DB isn't the same as what's being used in the application
37 | $this->assertNotSame($application_secret, $database_secret);
38 |
39 | // Then when we decrypt the secret, it is the same.
40 | $this->assertSame($application_secret, decrypt($database_secret));
41 | } else {
42 | $this->assertSame($application_secret, $database_secret);
43 | }
44 | }
45 |
46 | /** @test */
47 | public function enables_encryption_at_will()
48 | {
49 | // Given
50 | $hashed_passport = HashedPassport::withEncryption();
51 |
52 | // Then
53 | $this->assertTrue($hashed_passport::$withEncryption);
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/tests/TestCase.php:
--------------------------------------------------------------------------------
1 | artisan('migrate', ['--database' => 'testbench']);
19 | }
20 |
21 | protected function getPackageProviders($app)
22 | {
23 | return [
24 | PassportServiceProvider::class,
25 | HashidsServiceProvider::class,
26 | HashedPassportServiceProvider::class,
27 | ];
28 | }
29 |
30 | /**
31 | * Define environment setup.
32 | *
33 | * @param \Illuminate\Foundation\Application $app
34 | *
35 | * @return void
36 | */
37 | protected function getEnvironmentSetUp($app)
38 | {
39 | // Generate encryption key
40 | $app['config']->set('app.key', 'base64:' . base64_encode(Encrypter::generateKey($app['config']['app.cipher'])));
41 |
42 | // Setup default database to use sqlite :memory:
43 | $app['config']->set('database.default', 'testbench');
44 | $app['config']->set('database.connections.testbench', [
45 | 'driver' => 'sqlite',
46 | 'database' => ':memory:',
47 | 'prefix' => '',
48 | ]);
49 | }
50 |
51 | protected function createTestClient()
52 | {
53 | return Passport::client()->create([
54 | 'name' => 'Test Client',
55 | 'secret' => Str::random(40),
56 | 'redirect' => '',
57 | 'personal_access_client' => false,
58 | 'password_client' => false,
59 | 'revoked' => false,
60 | ])->fresh();
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/src/HashedPassportServiceProvider.php:
--------------------------------------------------------------------------------
1 | set_salt();
24 |
25 | $this->register_middleware($router);
26 |
27 | $this->register_observer();
28 |
29 | $this->load_routes();
30 |
31 | if ($this->app->runningInConsole()) {
32 | $this->register_console_commands_and_migrations();
33 |
34 | $this->publishes([
35 | __DIR__ . '/../config/hashed-passport.php' => config_path('hashed-passport.php'),
36 | ], 'config');
37 | }
38 | }
39 |
40 | /**
41 | * Register services.
42 | *
43 | * @return void
44 | */
45 | public function register()
46 | {
47 | $this->mergeConfigFrom(
48 | __DIR__ . '/../config/hashed-passport.php', 'hashed-passport'
49 | );
50 | }
51 |
52 | /*
53 | |--------------------------------------------------------------------------
54 | | Helpers
55 | |--------------------------------------------------------------------------
56 | |
57 | | To keep things cleaner
58 | |
59 | */
60 |
61 | /**
62 | * Registers the observer that handles the hashed client_id
63 | */
64 | private function register_observer()
65 | {
66 | $client = Passport::clientModel();
67 | $client::observe(ClientObserver::class);
68 | }
69 |
70 | /**
71 | * Overwrites the Passport routes after the app has loaded to ensure these are used.
72 | */
73 | private function load_routes()
74 | {
75 | $this->app->booted(function () {
76 | $this->loadRoutesFrom(__DIR__ . '/../routes/api.php');
77 | });
78 | }
79 |
80 | /**
81 | * Adds the encryption commands and migrations.
82 | */
83 | private function register_console_commands_and_migrations()
84 | {
85 | /**
86 | * Upgrades the secret column's max length from 100 to 2048 characters to support encrypted values.
87 | * Enables the manual encrypting and decrypting of the client secrets
88 | */
89 | if (Passport::$runsMigrations && HashedPassport::$withEncryption) {
90 | $this->loadMigrationsFrom(__DIR__ . '/../database/migrations');
91 |
92 | $this->commands([
93 | Install::class,
94 | Uninstall::class,
95 | ]);
96 | }
97 | }
98 |
99 | /**
100 | * Add the Hashids salt with the APP_KEY so it's unique, but constant
101 | */
102 | private function set_salt()
103 | {
104 | $this->app['config']['hashids.connections.hashed_passport'] = [
105 | 'salt' => config('hashed-passport.salt'),
106 | 'length' => '32',
107 | ];
108 | }
109 |
110 | /**
111 | * The middleware magic
112 | *
113 | * Catches both incoming and outgoing requests and should be compatible with custom routes
114 | */
115 | private function register_middleware(Router $router)
116 | {
117 | $router->middlewareGroup('hashed_passport', [
118 | Middleware\DecodeHashedClientIdOnRequest::class,
119 | ]);
120 | }
121 | }
122 |
--------------------------------------------------------------------------------
/src/Traits/HandlesEncryptedSecrets.php:
--------------------------------------------------------------------------------
1 | oauth_clients() as $oauth_client) {
25 | try {
26 | $decrypted_secret = decrypt($oauth_client->secret);
27 | \DB::table('oauth_clients')->where('id', $oauth_client->id)
28 | ->update(['secret' => $decrypted_secret]);
29 | } catch (DecryptException $e) {
30 | $this->write_to_console('Decryption for oauth_client with id: ' . $oauth_client->id .
31 | ' FAILED. Could be it was already decrypted.');
32 | $this->write_to_console('Stored secret:');
33 | $this->write_to_console($oauth_client->secret);
34 | }
35 | }
36 | }
37 |
38 | /**
39 | * Walk through all current oauth_clients using the DB facade to bypass the Observer and make sure
40 | * that all entries are saved with encryption.
41 | */
42 | private function encrypt_client_secrets()
43 | {
44 | foreach ($this->oauth_clients() as $oauth_client) {
45 | \DB::table('oauth_clients')->where('id', $oauth_client->id)
46 | ->update(['secret' => encrypt($oauth_client->secret)]);
47 | }
48 | }
49 |
50 | /*
51 | |--------------------------------------------------------------------------
52 | | Helpers
53 | |--------------------------------------------------------------------------
54 | |
55 | |
56 | |
57 | |
58 | */
59 |
60 | private function secrets_encrypted()
61 | {
62 | $this->write_to_console(" ");
63 | $this->write_to_console(" ");
64 | $this->write_to_console(" ");
65 | $this->write_to_console(" .---------------. ");
66 | $this->write_to_console(" / .-------------. \ ");
67 | $this->write_to_console(" / / \ \ ");
68 | $this->write_to_console(" | | | | ");
69 | $this->write_to_console(" _| |_______________| |_ ");
70 | $this->write_to_console(" .' |_| |_| '. ");
71 | $this->write_to_console(" '._____ ___________ _____.' ");
72 | $this->write_to_console(" | .'___________'. | ");
73 | $this->write_to_console(" '.__.'.' '.'.__.' ");
74 | $this->write_to_console(" '. | secrets | .' ");
75 | $this->write_to_console(" '.__ | encrypted | __.' ");
76 | $this->write_to_console(" | '.'.___________.'.' | ");
77 | $this->write_to_console(" '.____'.___________.'____.' ");
78 | $this->write_to_console(" '._______________________.' ");
79 | $this->write_to_console(" ");
80 | $this->write_to_console(" hashed-passport encryption active ");
81 | $this->write_to_console(" ");
82 | $this->write_to_console(" ");
83 | $this->write_to_console(" ");
84 | }
85 |
86 | private function secrets_decrypted()
87 | {
88 | $this->write_to_console(" ");
89 | $this->write_to_console(" ");
90 | $this->write_to_console(" ");
91 | $this->write_to_console(" .---------------. ");
92 | $this->write_to_console(" / .-------------. \ ");
93 | $this->write_to_console(" / / \ \ ");
94 | $this->write_to_console(" | | | | ");
95 | $this->write_to_console(" | | | | ");
96 | $this->write_to_console(" | | |_/ ");
97 | $this->write_to_console(" | | ");
98 | $this->write_to_console(" _| |___________________ ");
99 | $this->write_to_console(" .' |_| \_\ '. ");
100 | $this->write_to_console(" '._____ ___________ _____.' ");
101 | $this->write_to_console(" | .'___________'. | ");
102 | $this->write_to_console(" '.__.'.' '.'.__.' ");
103 | $this->write_to_console(" '. | secrets | .' ");
104 | $this->write_to_console(" '.__ | decrypted | __.' ");
105 | $this->write_to_console(" | '.'.___________.'.' | ");
106 | $this->write_to_console(" '.____'.___________.'____.' ");
107 | $this->write_to_console(" '._______________________.' ");
108 | $this->write_to_console(" ");
109 | $this->write_to_console(" hashed-passport encryption deactivated ");
110 | $this->write_to_console(" ");
111 | $this->write_to_console(" ");
112 | $this->write_to_console(" ");
113 | }
114 |
115 | /**
116 | * Writes to the console like an Artisan Command.
117 | *
118 | * @param $message
119 | */
120 | private function write_to_console($message)
121 | {
122 | $output = new \Symfony\Component\Console\Output\ConsoleOutput();
123 |
124 | $output->writeln($message);
125 | }
126 |
127 | /*
128 | |--------------------------------------------------------------------------
129 | | Getters and Setters
130 | |--------------------------------------------------------------------------
131 | |
132 | |
133 | |
134 | |
135 | */
136 |
137 | /**
138 | * @var $oauth_clients Collection containing all the oauth clients.
139 | */
140 | protected $oauth_clients;
141 |
142 | /**
143 | * Gets clients
144 | *
145 | * @return mixed
146 | */
147 | protected function oauth_clients()
148 | {
149 | return \DB::table('oauth_clients')->get();
150 | }
151 | }
152 |
--------------------------------------------------------------------------------
/readme.md:
--------------------------------------------------------------------------------
1 | Hashed Passport
2 | -----
3 | Hashed Passport turns Passport's public Client IDs from this:
4 |
5 | `client_id: 1`
6 |
7 | into the more pleasing, beautiful and industry standard:
8 |
9 | `client_id: AE20JvpmdYx34wD789Lng5jyqelQar8R`
10 |
11 | While not touching any of the core Passport files. It uses a middleware decode the `client_id` on routes and an observer to make the hashed id available through the `client_id` parameter of the `\Laravel\Passport\Client` anywhere in the application.
12 |
13 | Encryption of the client secrets is optional. These are saved in plain-text by default. After enabling this feature Hashed Passport turns a database entry of `wOVl4sBrTU46KwaiV56yc9IftikEIcKfWYCpwosG`
14 |
15 | into
16 |
17 | `eyJpdiI6IkhDQlYyZDBpeUVCVHRsZGFcL3ZiejRBPT0iLCJ2YWx1ZSI6InFoUGRKcUFRaVwvc2t3Q1ZhVHhqM3lpaW05cm1FaXpObUtyNmd4QXNMU21mVmNhNW45N0lVTHJLa2prYlJpcmpnQzJqMTRXS1c3NWlaR2tcL01ZZmFNXC9RPT0iLCJtYWMiOiJhYzJmOTMwZWE2NTI4MWZiMTAxNDg5NTQ2NmFiNDU2YmZmOTcxOTIzMTVmNTU2Njk1N2ZlNzg5MzFiNmI5MTUzIn0=`
18 |
19 | Introduction
20 | -----
21 |
22 | The idea for this package originated when I first started working with Laravel Passport. Having made a few APIs using Lumen and JWT it was jarring to discover that Passport used the auto-increment integer as the Client ID.
23 |
24 | The pros and cons are all listed in this 2 year old issue. You can tell just _how_ old it is by looking at the ID of the issue ;-)
25 |
26 | [Original Laravel/Passport Github Thread](https://github.com/laravel/passport/issues/14)
27 |
28 | Changelog
29 | ---
30 | * 1.0 - Non-intrusive implementation of hashed Passport client IDs.
31 | * 1.1 - Non-intrusive implementation of encrypted Passport client secrets.
32 | * 1.2 - Added the option to customise the hashing salt, cleaned up the code and improved the readme.
33 | * 2.0 - Works with Laravel Passport 7.0 and includes tests. Major thanks to Hackel and other contributors.
34 |
35 | Requirements
36 | -----
37 |
38 | **OPTIONAL: Encrypted Secrets**
39 | * A database supporting `VARCHAR(2048)`. If you use MySQL this means version 5.0.3+
40 |
41 |
42 | Installation
43 | -----
44 |
45 | ##### Hashed Client IDs
46 |
47 | * Install via composer `composer require ssmulders/hashed-passport`
48 |
49 | That's it! If you haven't tinkered with any default Laravel Passport routes, you're all set.
50 |
51 | ##### OPTIONAL: Encrypted Secrets
52 | * Add `HashedPassport::withEncryption();` to the register method of your `AppServiceProvider`.
53 |
54 | * Run the `php artisan migrate`
55 |
56 | * Run `php artisan hashed_passport:install`
57 |
58 | Voila! Your secrets are now stored with encryption and automatically decrypted after a DB retrieval.
59 |
60 | ##### OPTIONAL: Overwrite the APP_KEY Hashing Salt
61 | * Run `php artisan vendor:publish --provider="Ssmulders\HashedPassport\HashedPassportServiceProvider"`
62 |
63 | Now update the `salt` key in `config/hashed-passport.php` with a custom string.
64 |
65 | Further Usage and Customisation
66 | -----
67 |
68 | Anywhere you access the `Laravel\Passport\Client` model a `client_id` parameter is made available. This is the hashed client id.
69 |
70 | #### Add Middleware to additional Routes
71 | After installation `/oauth/token` route will now accept both the the hashed id and the regular integer id on incoming requests.
72 |
73 | To add this functionality to any other route, just attach the `hashed_passport` middleware like so:
74 |
75 | `Route::get('/oauth/clients', '\Laravel\Passport\Http\Controllers\ClientController@update')->middleware(['hashed_passport']);`
76 |
77 | The incoming hashed `client_id` string will now automatically be converted to it's integer value before being processed further by the application.
78 |
79 | #### Change the hash salt
80 | By default the hashing salt is the `APP_KEY`. To override this behaviour publish the config file to set a custom salt:
81 |
82 | `php artisan publish:config`
83 |
84 | How it works
85 | -----
86 |
87 | #### Hashed ID
88 | In order to work out-of-the-box the package overwrites the oAuth2 token route to accept the Client ID as a hashed string. Further more the hashed client id is made available on all Client models through the `client_id` parameter thanks to the `ClientObserver`. This same `ClientObserver` takes care of the encrypting and decrypting of the client secret (when enabled).
89 |
90 | The hashed id is still based on the `oauth_clients` table's `index` column. All it does is transform that ugly integer into a beautiful hashed string, Cinderella style.
91 |
92 | To do this a new connection is added to Hashids called `client_id`. This salt is based on your `APP_KEY` (unless configured otherwise).
93 |
94 | Supported grant types:
95 |
96 | `password`: **verified**
97 |
98 | `client_credentials`: **verified**
99 |
100 | `authorization_code`: **untested (probably needs the middleware added to other routes)**
101 |
102 | ##### Encrypted Secret
103 | Similar to the hashed ID, the observer catches the `Client` when it's being saved and retrieved from the database.
104 |
105 | Since the default `VARCHAR(100)` value for the `secret` column is insufficient for storing the lengthier encrypted secrets, that needs to be updated to `VARCHAR(2048)`. It could be less, but I'd rather be safe than sorry. The actual maximum column character length has no impact on storage usage.
106 |
107 | Running `php artisan hashed_passport:install` will then encrypt all the existing rows so their secret is encrypted. Once successful, you'll be greeted with a large lock. From now on all your client secrets are stored safely with Laravel's `encrypt()` helper.
108 |
109 |
110 |
111 | Troubleshooting
112 | -----
113 |
114 | * The package should be compatible with any installation and can even be used with projects that are using the integer client_id in production, as it will support both versions of the client_id and encrypt the secrets of all clients.
115 |
116 | * Check your routes to make sure that `/oauth/token` uses the `hashed_passport` middleware:
117 | `php artisan route:list`. The same applies for any other routes you want to accept requests with hashed `client_id` from.
118 |
119 |
120 | Uninstall
121 | -----
122 |
123 | Should support for hashed IDs and encrypted secrets be added to Laravel Passport in the future, all you'd need to do in order to revert back to normal is follow these steps:
124 |
125 | Run `php artisan hashed_passport:uninstall` to revert back to plain text secrets in your database.
126 |
127 | Run `composer remove ssmulders/hashed-passport` to remove the package.
128 |
129 | Remove `HashedPassport::withEncryption();` from your `AppServiceProvider`
130 |
131 | Run this SQL command `DELETE FROM 'migrations' WHERE migration LIKE '%hashed_passport%'` to update your migrations table and prevent rollback errors. `php artisan migrate:refresh` will work fine though.
132 |
133 | Feedback
134 | ---
135 |
136 | It's my first ever package so if you have any feedback on whatever, please leave a message! Learning how to create a package has opened up a whole new bag of appreciation for the wonder that's known as Laravel.
137 |
138 | Feel free to open pull request(s) that improve on the functionality, or fix any bugs.
139 |
140 | Credits
141 | ---
142 | Thanks to [@hfmikep](https://github.com/hfmikep) and [@nikkuang](https://github.com/nikkuang) for being the first to properly start tackling this long-standing feature request. And once again to [@hfmikep](https://github.com/hfmikep) for for creating the code that's used in the `UnHashClientIdOnRequest` middleware. And to [@corbosman](https://github.com/corbosman) for requesting the client secret encryption.
143 |
144 | License
145 | ---
146 | Copyright (c) 2018 Stan Smulders
147 |
148 | MIT License
149 |
150 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
151 |
152 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
153 |
154 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
155 |
156 |
--------------------------------------------------------------------------------