Bladeren bron

Updated to Passport for API

Will Browning 5 jaren geleden
bovenliggende
commit
81f7b35c04

+ 0 - 31
app/Http/Controllers/Api/ApiTokenController.php

@@ -1,31 +0,0 @@
-<?php
-
-namespace App\Http\Controllers\Api;
-
-use App\Http\Controllers\Controller;
-use Illuminate\Support\Str;
-
-class ApiTokenController extends Controller
-{
-    public function update()
-    {
-        $token = Str::random(60);
-
-        user()->forceFill([
-            'api_token' => hash('sha256', $token),
-        ])->save();
-
-        return response()->json([
-            'token' => $token
-        ]);
-    }
-
-    public function destroy()
-    {
-        user()->forceFill([
-            'api_token' => null,
-        ])->save();
-
-        return response('', 204);
-    }
-}

+ 1 - 0
app/Http/Kernel.php

@@ -36,6 +36,7 @@ class Kernel extends HttpKernel
             \Illuminate\View\Middleware\ShareErrorsFromSession::class,
             \App\Http\Middleware\VerifyCsrfToken::class,
             \Illuminate\Routing\Middleware\SubstituteBindings::class,
+            \Laravel\Passport\Http\Middleware\CreateFreshApiToken::class,
         ],
 
         'api' => [

+ 8 - 1
app/Providers/AuthServiceProvider.php

@@ -3,6 +3,7 @@
 namespace App\Providers;
 
 use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;
+use Laravel\Passport\Passport;
 
 class AuthServiceProvider extends ServiceProvider
 {
@@ -24,6 +25,12 @@ class AuthServiceProvider extends ServiceProvider
     {
         $this->registerPolicies();
 
-        //
+        Passport::routes(function ($router) {
+            $router->forPersonalAccessTokens();
+        }, ['middleware' => ['web', 'auth', '2fa']]);
+
+        Passport::personalAccessClientId(1);
+
+        Passport::cookie('anonaddy_token');
     }
 }

+ 2 - 2
app/User.php

@@ -7,10 +7,11 @@ use App\Traits\HasUuid;
 use Illuminate\Contracts\Auth\MustVerifyEmail;
 use Illuminate\Foundation\Auth\User as Authenticatable;
 use Illuminate\Notifications\Notifiable;
+use Laravel\Passport\HasApiTokens;
 
 class User extends Authenticatable implements MustVerifyEmail
 {
-    use Notifiable, HasUuid, HasEncryptedAttributes;
+    use Notifiable, HasUuid, HasEncryptedAttributes, HasApiTokens;
 
     public $incrementing = false;
 
@@ -48,7 +49,6 @@ class User extends Authenticatable implements MustVerifyEmail
      */
     protected $hidden = [
         'password',
-        'api_token',
         'remember_token',
         'two_factor_secret',
         'two_factor_backup_code'

+ 1 - 0
composer.json

@@ -13,6 +13,7 @@
         "doctrine/dbal": "^2.9",
         "fideloper/proxy": "^4.0",
         "laravel/framework": "^6.0",
+        "laravel/passport": "^7.5",
         "laravel/tinker": "^1.0",
         "mews/captcha": "^3.0.0",
         "php-mime-mail-parser/php-mime-mail-parser": "^5.0",

+ 755 - 1
composer.lock

@@ -4,7 +4,7 @@
         "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
         "This file is @generated automatically"
     ],
-    "content-hash": "132485a7a29ab64721297f7313af06ab",
+    "content-hash": "846b20a027e54de27b2ec80f3f84770d",
     "packages": [
         {
             "name": "bacon/bacon-qr-code",
@@ -97,6 +97,69 @@
             ],
             "time": "2017-10-25T22:45:27+00:00"
         },
+        {
+            "name": "defuse/php-encryption",
+            "version": "v2.2.1",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/defuse/php-encryption.git",
+                "reference": "0f407c43b953d571421e0020ba92082ed5fb7620"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/defuse/php-encryption/zipball/0f407c43b953d571421e0020ba92082ed5fb7620",
+                "reference": "0f407c43b953d571421e0020ba92082ed5fb7620",
+                "shasum": ""
+            },
+            "require": {
+                "ext-openssl": "*",
+                "paragonie/random_compat": ">= 2",
+                "php": ">=5.4.0"
+            },
+            "require-dev": {
+                "nikic/php-parser": "^2.0|^3.0|^4.0",
+                "phpunit/phpunit": "^4|^5"
+            },
+            "bin": [
+                "bin/generate-defuse-key"
+            ],
+            "type": "library",
+            "autoload": {
+                "psr-4": {
+                    "Defuse\\Crypto\\": "src"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Taylor Hornby",
+                    "email": "taylor@defuse.ca",
+                    "homepage": "https://defuse.ca/"
+                },
+                {
+                    "name": "Scott Arciszewski",
+                    "email": "info@paragonie.com",
+                    "homepage": "https://paragonie.com"
+                }
+            ],
+            "description": "Secure PHP Encryption Library",
+            "keywords": [
+                "aes",
+                "authenticated encryption",
+                "cipher",
+                "crypto",
+                "cryptography",
+                "encrypt",
+                "encryption",
+                "openssl",
+                "security",
+                "symmetric key cryptography"
+            ],
+            "time": "2018-07-24T23:27:56+00:00"
+        },
         {
             "name": "dnoegel/php-xdg-base-dir",
             "version": "0.1",
@@ -702,6 +765,168 @@
             ],
             "time": "2019-09-03T16:45:42+00:00"
         },
+        {
+            "name": "firebase/php-jwt",
+            "version": "v5.0.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/firebase/php-jwt.git",
+                "reference": "9984a4d3a32ae7673d6971ea00bae9d0a1abba0e"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/firebase/php-jwt/zipball/9984a4d3a32ae7673d6971ea00bae9d0a1abba0e",
+                "reference": "9984a4d3a32ae7673d6971ea00bae9d0a1abba0e",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.3.0"
+            },
+            "require-dev": {
+                "phpunit/phpunit": " 4.8.35"
+            },
+            "type": "library",
+            "autoload": {
+                "psr-4": {
+                    "Firebase\\JWT\\": "src"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "BSD-3-Clause"
+            ],
+            "authors": [
+                {
+                    "name": "Neuman Vong",
+                    "email": "neuman+pear@twilio.com",
+                    "role": "Developer"
+                },
+                {
+                    "name": "Anant Narayanan",
+                    "email": "anant@php.net",
+                    "role": "Developer"
+                }
+            ],
+            "description": "A simple library to encode and decode JSON Web Tokens (JWT) in PHP. Should conform to the current spec.",
+            "homepage": "https://github.com/firebase/php-jwt",
+            "time": "2017-06-27T22:17:23+00:00"
+        },
+        {
+            "name": "guzzlehttp/guzzle",
+            "version": "6.3.3",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/guzzle/guzzle.git",
+                "reference": "407b0cb880ace85c9b63c5f9551db498cb2d50ba"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/guzzle/guzzle/zipball/407b0cb880ace85c9b63c5f9551db498cb2d50ba",
+                "reference": "407b0cb880ace85c9b63c5f9551db498cb2d50ba",
+                "shasum": ""
+            },
+            "require": {
+                "guzzlehttp/promises": "^1.0",
+                "guzzlehttp/psr7": "^1.4",
+                "php": ">=5.5"
+            },
+            "require-dev": {
+                "ext-curl": "*",
+                "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.4 || ^7.0",
+                "psr/log": "^1.0"
+            },
+            "suggest": {
+                "psr/log": "Required for using the Log middleware"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "6.3-dev"
+                }
+            },
+            "autoload": {
+                "files": [
+                    "src/functions_include.php"
+                ],
+                "psr-4": {
+                    "GuzzleHttp\\": "src/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Michael Dowling",
+                    "email": "mtdowling@gmail.com",
+                    "homepage": "https://github.com/mtdowling"
+                }
+            ],
+            "description": "Guzzle is a PHP HTTP client library",
+            "homepage": "http://guzzlephp.org/",
+            "keywords": [
+                "client",
+                "curl",
+                "framework",
+                "http",
+                "http client",
+                "rest",
+                "web service"
+            ],
+            "time": "2018-04-22T15:46:56+00:00"
+        },
+        {
+            "name": "guzzlehttp/promises",
+            "version": "v1.3.1",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/guzzle/promises.git",
+                "reference": "a59da6cf61d80060647ff4d3eb2c03a2bc694646"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/guzzle/promises/zipball/a59da6cf61d80060647ff4d3eb2c03a2bc694646",
+                "reference": "a59da6cf61d80060647ff4d3eb2c03a2bc694646",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.5.0"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "^4.0"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "1.4-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "GuzzleHttp\\Promise\\": "src/"
+                },
+                "files": [
+                    "src/functions_include.php"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Michael Dowling",
+                    "email": "mtdowling@gmail.com",
+                    "homepage": "https://github.com/mtdowling"
+                }
+            ],
+            "description": "Guzzle promises library",
+            "keywords": [
+                "promise"
+            ],
+            "time": "2016-12-20T10:07:11+00:00"
+        },
         {
             "name": "guzzlehttp/psr7",
             "version": "1.6.1",
@@ -1077,6 +1302,77 @@
             ],
             "time": "2019-10-08T12:50:06+00:00"
         },
+        {
+            "name": "laravel/passport",
+            "version": "v7.5.1",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/laravel/passport.git",
+                "reference": "d63cdd672c3d65b3c35b73d0ef13a9dbfcb71c08"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/laravel/passport/zipball/d63cdd672c3d65b3c35b73d0ef13a9dbfcb71c08",
+                "reference": "d63cdd672c3d65b3c35b73d0ef13a9dbfcb71c08",
+                "shasum": ""
+            },
+            "require": {
+                "ext-json": "*",
+                "firebase/php-jwt": "~3.0|~4.0|~5.0",
+                "guzzlehttp/guzzle": "~6.0",
+                "illuminate/auth": "~5.6.0|~5.7.0|~5.8.0|^6.0|^7.0",
+                "illuminate/console": "~5.6.0|~5.7.0|~5.8.0|^6.0|^7.0",
+                "illuminate/container": "~5.6.0|~5.7.0|~5.8.0|^6.0|^7.0",
+                "illuminate/contracts": "~5.6.0|~5.7.0|~5.8.0|^6.0|^7.0",
+                "illuminate/cookie": "~5.6.0|~5.7.0|~5.8.0|^6.0|^7.0",
+                "illuminate/database": "~5.6.0|~5.7.0|~5.8.0|^6.0|^7.0",
+                "illuminate/encryption": "~5.6.0|~5.7.0|~5.8.0|^6.0|^7.0",
+                "illuminate/http": "~5.6.0|~5.7.0|~5.8.0|^6.0|^7.0",
+                "illuminate/support": "~5.6.0|~5.7.0|~5.8.0|^6.0|^7.0",
+                "league/oauth2-server": "^7.0",
+                "php": ">=7.1",
+                "phpseclib/phpseclib": "^2.0",
+                "symfony/psr-http-message-bridge": "~1.0",
+                "zendframework/zend-diactoros": "~1.0|~2.0"
+            },
+            "require-dev": {
+                "mockery/mockery": "^1.0",
+                "phpunit/phpunit": "^7.4|^8.0"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "7.0-dev"
+                },
+                "laravel": {
+                    "providers": [
+                        "Laravel\\Passport\\PassportServiceProvider"
+                    ]
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Laravel\\Passport\\": "src/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Taylor Otwell",
+                    "email": "taylor@laravel.com"
+                }
+            ],
+            "description": "Laravel Passport provides OAuth2 server support to Laravel.",
+            "keywords": [
+                "laravel",
+                "oauth",
+                "passport"
+            ],
+            "time": "2019-10-08T16:45:24+00:00"
+        },
         {
             "name": "laravel/tinker",
             "version": "v1.0.10",
@@ -1140,6 +1436,111 @@
             ],
             "time": "2019-08-07T15:10:45+00:00"
         },
+        {
+            "name": "lcobucci/jwt",
+            "version": "3.3.1",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/lcobucci/jwt.git",
+                "reference": "a11ec5f4b4d75d1fcd04e133dede4c317aac9e18"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/lcobucci/jwt/zipball/a11ec5f4b4d75d1fcd04e133dede4c317aac9e18",
+                "reference": "a11ec5f4b4d75d1fcd04e133dede4c317aac9e18",
+                "shasum": ""
+            },
+            "require": {
+                "ext-mbstring": "*",
+                "ext-openssl": "*",
+                "php": "^5.6 || ^7.0"
+            },
+            "require-dev": {
+                "mikey179/vfsstream": "~1.5",
+                "phpmd/phpmd": "~2.2",
+                "phpunit/php-invoker": "~1.1",
+                "phpunit/phpunit": "^5.7 || ^7.3",
+                "squizlabs/php_codesniffer": "~2.3"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "3.1-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Lcobucci\\JWT\\": "src"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "BSD-3-Clause"
+            ],
+            "authors": [
+                {
+                    "name": "Luís Otávio Cobucci Oblonczyk",
+                    "email": "lcobucci@gmail.com",
+                    "role": "Developer"
+                }
+            ],
+            "description": "A simple library to work with JSON Web Token and JSON Web Signature",
+            "keywords": [
+                "JWS",
+                "jwt"
+            ],
+            "time": "2019-05-24T18:30:49+00:00"
+        },
+        {
+            "name": "league/event",
+            "version": "2.2.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/thephpleague/event.git",
+                "reference": "d2cc124cf9a3fab2bb4ff963307f60361ce4d119"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/thephpleague/event/zipball/d2cc124cf9a3fab2bb4ff963307f60361ce4d119",
+                "reference": "d2cc124cf9a3fab2bb4ff963307f60361ce4d119",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.4.0"
+            },
+            "require-dev": {
+                "henrikbjorn/phpspec-code-coverage": "~1.0.1",
+                "phpspec/phpspec": "^2.2"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "2.2-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "League\\Event\\": "src/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Frank de Jonge",
+                    "email": "info@frenky.net"
+                }
+            ],
+            "description": "Event package",
+            "keywords": [
+                "emitter",
+                "event",
+                "listener"
+            ],
+            "time": "2018-11-26T11:52:41+00:00"
+        },
         {
             "name": "league/flysystem",
             "version": "1.0.55",
@@ -1224,6 +1625,83 @@
             ],
             "time": "2019-08-24T11:17:19+00:00"
         },
+        {
+            "name": "league/oauth2-server",
+            "version": "7.4.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/thephpleague/oauth2-server.git",
+                "reference": "2eb1cf79e59d807d89c256e7ac5e2bf8bdbd4acf"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/thephpleague/oauth2-server/zipball/2eb1cf79e59d807d89c256e7ac5e2bf8bdbd4acf",
+                "reference": "2eb1cf79e59d807d89c256e7ac5e2bf8bdbd4acf",
+                "shasum": ""
+            },
+            "require": {
+                "defuse/php-encryption": "^2.1",
+                "ext-openssl": "*",
+                "lcobucci/jwt": "^3.2.2",
+                "league/event": "^2.1",
+                "php": ">=7.0.0",
+                "psr/http-message": "^1.0.1"
+            },
+            "replace": {
+                "league/oauth2server": "*",
+                "lncd/oauth2": "*"
+            },
+            "require-dev": {
+                "phpstan/phpstan": "^0.9.2",
+                "phpstan/phpstan-phpunit": "^0.9.4",
+                "phpstan/phpstan-strict-rules": "^0.9.0",
+                "phpunit/phpunit": "^6.3 || ^7.0",
+                "roave/security-advisories": "dev-master",
+                "zendframework/zend-diactoros": "^1.3.2"
+            },
+            "type": "library",
+            "autoload": {
+                "psr-4": {
+                    "League\\OAuth2\\Server\\": "src/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Alex Bilbie",
+                    "email": "hello@alexbilbie.com",
+                    "homepage": "http://www.alexbilbie.com",
+                    "role": "Developer"
+                },
+                {
+                    "name": "Andy Millington",
+                    "email": "andrew@noexceptions.io",
+                    "homepage": "https://www.noexceptions.io",
+                    "role": "Developer"
+                }
+            ],
+            "description": "A lightweight and powerful OAuth 2.0 authorization and resource server library with support for all the core specification grants. This library will allow you to secure your API with OAuth and allow your applications users to approve apps that want to access their data from your API.",
+            "homepage": "https://oauth2.thephpleague.com/",
+            "keywords": [
+                "Authentication",
+                "api",
+                "auth",
+                "authorisation",
+                "authorization",
+                "oauth",
+                "oauth 2",
+                "oauth 2.0",
+                "oauth2",
+                "protect",
+                "resource",
+                "secure",
+                "server"
+            ],
+            "time": "2019-05-05T09:22:01+00:00"
+        },
         {
             "name": "mews/captcha",
             "version": "3.0.1",
@@ -1792,6 +2270,98 @@
             ],
             "time": "2015-07-25T16:39:46+00:00"
         },
+        {
+            "name": "phpseclib/phpseclib",
+            "version": "2.0.23",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/phpseclib/phpseclib.git",
+                "reference": "c78eb5058d5bb1a183133c36d4ba5b6675dfa099"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/phpseclib/phpseclib/zipball/c78eb5058d5bb1a183133c36d4ba5b6675dfa099",
+                "reference": "c78eb5058d5bb1a183133c36d4ba5b6675dfa099",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.3.3"
+            },
+            "require-dev": {
+                "phing/phing": "~2.7",
+                "phpunit/phpunit": "^4.8.35|^5.7|^6.0",
+                "sami/sami": "~2.0",
+                "squizlabs/php_codesniffer": "~2.0"
+            },
+            "suggest": {
+                "ext-gmp": "Install the GMP (GNU Multiple Precision) extension in order to speed up arbitrary precision integer arithmetic operations.",
+                "ext-libsodium": "SSH2/SFTP can make use of some algorithms provided by the libsodium-php extension.",
+                "ext-mcrypt": "Install the Mcrypt extension in order to speed up a few other cryptographic operations.",
+                "ext-openssl": "Install the OpenSSL extension in order to speed up a wide variety of cryptographic operations."
+            },
+            "type": "library",
+            "autoload": {
+                "files": [
+                    "phpseclib/bootstrap.php"
+                ],
+                "psr-4": {
+                    "phpseclib\\": "phpseclib/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Jim Wigginton",
+                    "email": "terrafrost@php.net",
+                    "role": "Lead Developer"
+                },
+                {
+                    "name": "Patrick Monnerat",
+                    "email": "pm@datasphere.ch",
+                    "role": "Developer"
+                },
+                {
+                    "name": "Andreas Fischer",
+                    "email": "bantu@phpbb.com",
+                    "role": "Developer"
+                },
+                {
+                    "name": "Hans-Jürgen Petrich",
+                    "email": "petrich@tronic-media.com",
+                    "role": "Developer"
+                },
+                {
+                    "name": "Graham Campbell",
+                    "email": "graham@alt-three.com",
+                    "role": "Developer"
+                }
+            ],
+            "description": "PHP Secure Communications Library - Pure-PHP implementations of RSA, AES, SSH2, SFTP, X.509 etc.",
+            "homepage": "http://phpseclib.sourceforge.net",
+            "keywords": [
+                "BigInteger",
+                "aes",
+                "asn.1",
+                "asn1",
+                "blowfish",
+                "crypto",
+                "cryptography",
+                "encryption",
+                "rsa",
+                "security",
+                "sftp",
+                "signature",
+                "signing",
+                "ssh",
+                "twofish",
+                "x.509",
+                "x509"
+            ],
+            "time": "2019-09-17T03:41:22+00:00"
+        },
         {
             "name": "pragmarx/google2fa",
             "version": "v6.1.0",
@@ -2076,6 +2646,58 @@
             ],
             "time": "2017-02-14T16:28:37+00:00"
         },
+        {
+            "name": "psr/http-factory",
+            "version": "1.0.1",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/php-fig/http-factory.git",
+                "reference": "12ac7fcd07e5b077433f5f2bee95b3a771bf61be"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/php-fig/http-factory/zipball/12ac7fcd07e5b077433f5f2bee95b3a771bf61be",
+                "reference": "12ac7fcd07e5b077433f5f2bee95b3a771bf61be",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=7.0.0",
+                "psr/http-message": "^1.0"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "1.0.x-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Psr\\Http\\Message\\": "src/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "PHP-FIG",
+                    "homepage": "http://www.php-fig.org/"
+                }
+            ],
+            "description": "Common interfaces for PSR-7 HTTP message factories",
+            "keywords": [
+                "factory",
+                "http",
+                "message",
+                "psr",
+                "psr-17",
+                "psr-7",
+                "request",
+                "response"
+            ],
+            "time": "2019-04-30T12:38:16+00:00"
+        },
         {
             "name": "psr/http-message",
             "version": "1.0.1",
@@ -3607,6 +4229,71 @@
             "homepage": "https://symfony.com",
             "time": "2019-09-26T21:17:10+00:00"
         },
+        {
+            "name": "symfony/psr-http-message-bridge",
+            "version": "v1.2.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/symfony/psr-http-message-bridge.git",
+                "reference": "9ab9d71f97d5c7d35a121a7fb69f74fee95cd0ad"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/symfony/psr-http-message-bridge/zipball/9ab9d71f97d5c7d35a121a7fb69f74fee95cd0ad",
+                "reference": "9ab9d71f97d5c7d35a121a7fb69f74fee95cd0ad",
+                "shasum": ""
+            },
+            "require": {
+                "php": "^7.1",
+                "psr/http-message": "^1.0",
+                "symfony/http-foundation": "^3.4 || ^4.0"
+            },
+            "require-dev": {
+                "nyholm/psr7": "^1.1",
+                "symfony/phpunit-bridge": "^3.4.20 || ^4.0",
+                "zendframework/zend-diactoros": "^1.4.1 || ^2.0"
+            },
+            "suggest": {
+                "nyholm/psr7": "For a super lightweight PSR-7/17 implementation"
+            },
+            "type": "symfony-bridge",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "1.2-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Symfony\\Bridge\\PsrHttpMessage\\": ""
+                },
+                "exclude-from-classmap": [
+                    "/Tests/"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Symfony Community",
+                    "homepage": "http://symfony.com/contributors"
+                },
+                {
+                    "name": "Fabien Potencier",
+                    "email": "fabien@symfony.com"
+                }
+            ],
+            "description": "PSR HTTP message bridge",
+            "homepage": "http://symfony.com",
+            "keywords": [
+                "http",
+                "http-message",
+                "psr-17",
+                "psr-7"
+            ],
+            "time": "2019-03-11T18:22:33+00:00"
+        },
         {
             "name": "symfony/routing",
             "version": "v4.3.5",
@@ -4053,6 +4740,73 @@
                 "environment"
             ],
             "time": "2019-09-10T21:37:39+00:00"
+        },
+        {
+            "name": "zendframework/zend-diactoros",
+            "version": "2.1.5",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/zendframework/zend-diactoros.git",
+                "reference": "6dcf9e760a6b476f3e9d80abbc9ce9c4aa921f9c"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/zendframework/zend-diactoros/zipball/6dcf9e760a6b476f3e9d80abbc9ce9c4aa921f9c",
+                "reference": "6dcf9e760a6b476f3e9d80abbc9ce9c4aa921f9c",
+                "shasum": ""
+            },
+            "require": {
+                "php": "^7.1",
+                "psr/http-factory": "^1.0",
+                "psr/http-message": "^1.0"
+            },
+            "provide": {
+                "psr/http-factory-implementation": "1.0",
+                "psr/http-message-implementation": "1.0"
+            },
+            "require-dev": {
+                "ext-curl": "*",
+                "ext-dom": "*",
+                "ext-libxml": "*",
+                "http-interop/http-factory-tests": "^0.5.0",
+                "php-http/psr7-integration-tests": "dev-master",
+                "phpunit/phpunit": "^7.0.2",
+                "zendframework/zend-coding-standard": "~1.0.0"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "2.1.x-dev",
+                    "dev-develop": "2.2.x-dev",
+                    "dev-release-1.8": "1.8.x-dev"
+                }
+            },
+            "autoload": {
+                "files": [
+                    "src/functions/create_uploaded_file.php",
+                    "src/functions/marshal_headers_from_sapi.php",
+                    "src/functions/marshal_method_from_sapi.php",
+                    "src/functions/marshal_protocol_version_from_sapi.php",
+                    "src/functions/marshal_uri_from_sapi.php",
+                    "src/functions/normalize_server.php",
+                    "src/functions/normalize_uploaded_files.php",
+                    "src/functions/parse_cookie_header.php"
+                ],
+                "psr-4": {
+                    "Zend\\Diactoros\\": "src/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "BSD-3-Clause"
+            ],
+            "description": "PSR HTTP Message implementations",
+            "keywords": [
+                "http",
+                "psr",
+                "psr-7"
+            ],
+            "time": "2019-10-10T17:38:20+00:00"
         }
     ],
     "packages-dev": [

+ 1 - 2
config/auth.php

@@ -42,9 +42,8 @@ return [
         ],
 
         'api' => [
-            'driver' => 'token',
+            'driver' => 'passport',
             'provider' => 'users',
-            'hash' => true,
         ],
     ],
 

+ 35 - 0
database/migrations/2016_06_01_000001_create_oauth_auth_codes_table.php

@@ -0,0 +1,35 @@
+<?php
+
+use Illuminate\Database\Migrations\Migration;
+use Illuminate\Database\Schema\Blueprint;
+use Illuminate\Support\Facades\Schema;
+
+class CreateOauthAuthCodesTable extends Migration
+{
+    /**
+     * Run the migrations.
+     *
+     * @return void
+     */
+    public function up()
+    {
+        Schema::create('oauth_auth_codes', function (Blueprint $table) {
+            $table->string('id', 100)->primary();
+            $table->uuid('user_id');
+            $table->unsignedInteger('client_id');
+            $table->text('scopes')->nullable();
+            $table->boolean('revoked');
+            $table->dateTime('expires_at')->nullable();
+        });
+    }
+
+    /**
+     * Reverse the migrations.
+     *
+     * @return void
+     */
+    public function down()
+    {
+        Schema::dropIfExists('oauth_auth_codes');
+    }
+}

+ 37 - 0
database/migrations/2016_06_01_000002_create_oauth_access_tokens_table.php

@@ -0,0 +1,37 @@
+<?php
+
+use Illuminate\Database\Migrations\Migration;
+use Illuminate\Database\Schema\Blueprint;
+use Illuminate\Support\Facades\Schema;
+
+class CreateOauthAccessTokensTable extends Migration
+{
+    /**
+     * Run the migrations.
+     *
+     * @return void
+     */
+    public function up()
+    {
+        Schema::create('oauth_access_tokens', function (Blueprint $table) {
+            $table->string('id', 100)->primary();
+            $table->uuid('user_id')->index()->nullable();
+            $table->unsignedInteger('client_id');
+            $table->string('name')->nullable();
+            $table->text('scopes')->nullable();
+            $table->boolean('revoked');
+            $table->timestamps();
+            $table->dateTime('expires_at')->nullable();
+        });
+    }
+
+    /**
+     * Reverse the migrations.
+     *
+     * @return void
+     */
+    public function down()
+    {
+        Schema::dropIfExists('oauth_access_tokens');
+    }
+}

+ 33 - 0
database/migrations/2016_06_01_000003_create_oauth_refresh_tokens_table.php

@@ -0,0 +1,33 @@
+<?php
+
+use Illuminate\Database\Migrations\Migration;
+use Illuminate\Database\Schema\Blueprint;
+use Illuminate\Support\Facades\Schema;
+
+class CreateOauthRefreshTokensTable extends Migration
+{
+    /**
+     * Run the migrations.
+     *
+     * @return void
+     */
+    public function up()
+    {
+        Schema::create('oauth_refresh_tokens', function (Blueprint $table) {
+            $table->string('id', 100)->primary();
+            $table->string('access_token_id', 100)->index();
+            $table->boolean('revoked');
+            $table->dateTime('expires_at')->nullable();
+        });
+    }
+
+    /**
+     * Reverse the migrations.
+     *
+     * @return void
+     */
+    public function down()
+    {
+        Schema::dropIfExists('oauth_refresh_tokens');
+    }
+}

+ 38 - 0
database/migrations/2016_06_01_000004_create_oauth_clients_table.php

@@ -0,0 +1,38 @@
+<?php
+
+use Illuminate\Database\Migrations\Migration;
+use Illuminate\Database\Schema\Blueprint;
+use Illuminate\Support\Facades\Schema;
+
+class CreateOauthClientsTable extends Migration
+{
+    /**
+     * Run the migrations.
+     *
+     * @return void
+     */
+    public function up()
+    {
+        Schema::create('oauth_clients', function (Blueprint $table) {
+            $table->increments('id');
+            $table->uuid('user_id')->index()->nullable();
+            $table->string('name');
+            $table->string('secret', 100);
+            $table->text('redirect');
+            $table->boolean('personal_access_client');
+            $table->boolean('password_client');
+            $table->boolean('revoked');
+            $table->timestamps();
+        });
+    }
+
+    /**
+     * Reverse the migrations.
+     *
+     * @return void
+     */
+    public function down()
+    {
+        Schema::dropIfExists('oauth_clients');
+    }
+}

+ 32 - 0
database/migrations/2016_06_01_000005_create_oauth_personal_access_clients_table.php

@@ -0,0 +1,32 @@
+<?php
+
+use Illuminate\Database\Migrations\Migration;
+use Illuminate\Database\Schema\Blueprint;
+use Illuminate\Support\Facades\Schema;
+
+class CreateOauthPersonalAccessClientsTable extends Migration
+{
+    /**
+     * Run the migrations.
+     *
+     * @return void
+     */
+    public function up()
+    {
+        Schema::create('oauth_personal_access_clients', function (Blueprint $table) {
+            $table->increments('id');
+            $table->unsignedInteger('client_id')->index();
+            $table->timestamps();
+        });
+    }
+
+    /**
+     * Reverse the migrations.
+     *
+     * @return void
+     */
+    public function down()
+    {
+        Schema::dropIfExists('oauth_personal_access_clients');
+    }
+}

+ 0 - 36
database/migrations/2019_09_30_155717_add_api_token_column_to_users_table.php

@@ -1,36 +0,0 @@
-<?php
-
-use Illuminate\Database\Migrations\Migration;
-use Illuminate\Database\Schema\Blueprint;
-use Illuminate\Support\Facades\Schema;
-
-class AddApiTokenColumnToUsersTable extends Migration
-{
-    /**
-     * Run the migrations.
-     *
-     * @return void
-     */
-    public function up()
-    {
-        Schema::table('users', function (Blueprint $table) {
-            $table->string('api_token', 80)
-                        ->after('password')
-                        ->unique()
-                        ->nullable()
-                        ->default(null);
-        });
-    }
-
-    /**
-     * Reverse the migrations.
-     *
-     * @return void
-     */
-    public function down()
-    {
-        Schema::table('users', function (Blueprint $table) {
-            $table->dropColumn('api_token');
-        });
-    }
-}

+ 5 - 0
resources/js/app.js

@@ -31,6 +31,11 @@ Vue.component('recipients', require('./pages/Recipients.vue').default)
 Vue.component('domains', require('./pages/Domains.vue').default)
 Vue.component('usernames', require('./pages/Usernames.vue').default)
 
+Vue.component(
+  'passport-personal-access-tokens',
+  require('./components/passport/PersonalAccessTokens.vue').default
+)
+
 Vue.filter('formatDate', value => {
   return dayjs(value).format('Do MMM YYYY')
 })

+ 323 - 0
resources/js/components/passport/PersonalAccessTokens.vue

@@ -0,0 +1,323 @@
+<template>
+  <div>
+    <h3 class="font-bold text-xl">
+      Information
+    </h3>
+
+    <div class="mt-4 w-24 border-b-2 border-grey-200"></div>
+
+    <p class="my-6">
+      Your API access tokens can be used with the
+      <a
+        href="https://github.com/anonaddy/browser-extension"
+        target="_blank"
+        rel="nofollow noopener noreferrer"
+        class="text-indigo-700"
+        >open-source</a
+      >
+      AnonAddy browser extension on
+      <a
+        href="https://addons.mozilla.org/en-GB/firefox/addon/anonaddy/"
+        target="_blank"
+        rel="nofollow noopener noreferrer"
+        class="text-indigo-700"
+        >Firefox</a
+      >
+      or
+      <a
+        href="https://chrome.google.com/webstore/detail/anonaddy/iadbdpnoknmbdeolbapdackdcogdmjpe"
+        target="_blank"
+        rel="nofollow noopener noreferrer"
+        class="text-indigo-700"
+        >Chrome / Brave</a
+      >
+      to generate UUID aliases. Simply paste the token generated below into the browser extension to
+      get started. Your API Access tokens are secret and should be treated like your password.
+    </p>
+
+    <button
+      @click="openCreateTokenModal"
+      class="bg-cyan-400 w-full hover:bg-cyan-300 text-cyan-900 font-bold py-3 px-4 rounded focus:outline-none"
+    >
+      Generate New Token
+    </button>
+
+    <div class="mt-6">
+      <h3 class="font-bold text-xl">
+        Personal Access Tokens
+      </h3>
+
+      <div class="my-4 w-24 border-b-2 border-grey-200"></div>
+
+      <p class="my-6">
+        Tokens you have generated that can be used to access the AnonAddy API. To revoke an access
+        token simply click the delete button next to it.
+      </p>
+
+      <div>
+        <p class="mb-0" v-if="tokens.length === 0">
+          You have not created any personal access tokens.
+        </p>
+
+        <div class="table w-full" v-if="tokens.length > 0">
+          <div class="table-row">
+            <div class="table-cell p-4 font-semibold">Name</div>
+            <div class="table-cell p-4 font-semibold">Created</div>
+            <div class="table-cell p-4 font-semibold">Expires</div>
+            <div class="table-cell p-4"></div>
+          </div>
+          <div
+            v-for="token in tokens"
+            :key="token.id"
+            class="table-row even:bg-grey-50 odd:bg-white"
+          >
+            <div class="table-cell p-4">{{ token.name }}</div>
+            <div class="table-cell p-4">{{ token.created_at | timeAgo }}</div>
+            <div class="table-cell p-4">{{ token.expires_at | timeAgo }}</div>
+            <div class="table-cell p-4 text-right">
+              <a
+                class="text-red-500 font-bold cursor-pointer focus:outline-none"
+                @click="showRevokeModal(token)"
+              >
+                Delete
+              </a>
+            </div>
+          </div>
+        </div>
+      </div>
+    </div>
+
+    <Modal :open="createTokenModalOpen" @close="closeCreateTokenModal">
+      <div class="max-w-lg w-full bg-white rounded-lg shadow-2xl px-6 py-6">
+        <h2
+          class="font-semibold text-grey-900 text-2xl leading-tight border-b-2 border-grey-100 pb-4"
+        >
+          Create New Token
+        </h2>
+        <p class="mt-4 text-grey-700">
+          What's this token going to be used for? Give it a short name so that you remember later.
+        </p>
+        <div class="mt-6">
+          <div v-if="form.errors.length > 0" class="mb-3 text-red-500">
+            <ul>
+              <li v-for="error in form.errors" :key="error">
+                {{ error }}
+              </li>
+            </ul>
+          </div>
+          <label for="create-token-name" class="block text-grey-700 text-sm my-2">
+            Name:
+          </label>
+          <input
+            v-model="form.name"
+            type="text"
+            id="create-token-name"
+            class="w-full appearance-none bg-grey-100 border border-transparent text-grey-700 focus:outline-none rounded p-3 mb-6"
+            :class="form.errors.length > 0 ? 'border-red-500' : ''"
+            placeholder="e.g. Browser extension"
+            autofocus
+          />
+          <button
+            @click="store"
+            class="bg-cyan-400 hover:bg-cyan-300 text-cyan-900 font-bold py-3 px-4 rounded focus:outline-none"
+            :class="loading ? 'cursor-not-allowed' : ''"
+            :disabled="loading"
+          >
+            Generate Token
+            <loader v-if="loading" />
+          </button>
+          <button
+            @click="closeCreateTokenModal"
+            class="ml-4 px-4 py-3 text-grey-800 font-semibold bg-white hover:bg-grey-50 border border-grey-100 rounded focus:outline-none"
+          >
+            Close
+          </button>
+        </div>
+      </div>
+    </Modal>
+
+    <Modal :open="accessTokenModalOpen" @close="closeAccessTokenModal">
+      <div class="max-w-lg w-full bg-white rounded-lg shadow-2xl px-6 py-6">
+        <h2
+          class="font-semibold text-grey-900 text-2xl leading-tight border-b-2 border-grey-100 pb-4"
+        >
+          Personal Access Token
+        </h2>
+        <p class="my-4 text-grey-700">
+          This is your new personal access token. This is the only time the token will ever be
+          displayed, so please make a note of it in a safe place (e.g. password manager)!
+        </p>
+        <pre class="hidden md:flex p-3 text-grey-900 bg-white border rounded">
+            <code class="break-all whitespace-normal text-xs">{{ accessToken }}</code>
+        </pre>
+        <div
+          class="md:hidden text-sm border-t-8 rounded text-yellow-800 border-yellow-600 bg-yellow-100 px-3 py-4"
+          role="alert"
+        >
+          The token is too long to display on a small device, click the button below to copy it to
+          your clipboard.
+        </div>
+        <div class="mt-6">
+          <button
+            class="bg-cyan-400 hover:bg-cyan-300 text-cyan-900 font-bold py-3 px-4 rounded focus:outline-none"
+            v-clipboard="() => accessToken"
+            v-clipboard:success="clipboardSuccess"
+            v-clipboard:error="clipboardError"
+          >
+            Copy To Clipboard
+          </button>
+          <button
+            @click="closeAccessTokenModal"
+            class="ml-4 px-4 py-3 text-grey-800 font-semibold bg-white hover:bg-grey-50 border border-grey-100 rounded focus:outline-none"
+          >
+            Close
+          </button>
+        </div>
+      </div>
+    </Modal>
+
+    <Modal :open="revokeTokenModalOpen" @close="closeRevokeTokenModal">
+      <div class="max-w-lg w-full bg-white rounded-lg shadow-2xl px-6 py-6">
+        <h2
+          class="font-semibold text-grey-900 text-2xl leading-tight border-b-2 border-grey-100 pb-4"
+        >
+          Revoke API Access Token
+        </h2>
+        <p class="my-4 text-grey-700">
+          Any browser extension, application or script using this API access token will no longer be
+          able to access the AnonAddy API. This action cannot be undone.
+        </p>
+        <div class="mt-6">
+          <button
+            @click="revoke"
+            class="bg-red-500 hover:bg-red-600 text-white font-bold py-3 px-4 rounded focus:outline-none"
+            :class="revokeTokenLoading ? 'cursor-not-allowed' : ''"
+            :disabled="revokeTokenLoading"
+          >
+            Revoke Token
+            <loader v-if="revokeTokenLoading" />
+          </button>
+          <button
+            @click="closeRevokeTokenModal"
+            class="ml-4 px-4 py-3 text-grey-800 font-semibold bg-white hover:bg-grey-50 border border-grey-100 rounded focus:outline-none"
+          >
+            Close
+          </button>
+        </div>
+      </div>
+    </Modal>
+  </div>
+</template>
+
+<script>
+import Modal from './../Modal.vue'
+
+export default {
+  components: {
+    Modal,
+  },
+  data() {
+    return {
+      accessToken: null,
+      createTokenModalOpen: false,
+      accessTokenModalOpen: false,
+      revokeTokenModalOpen: false,
+      tokens: [],
+      tokenToRevoke: null,
+      form: {
+        name: '',
+        errors: [],
+      },
+      loading: false,
+      revokeTokenLoading: false,
+    }
+  },
+  mounted() {
+    this.getTokens()
+  },
+
+  methods: {
+    getTokens() {
+      axios.get('/oauth/personal-access-tokens').then(response => {
+        this.tokens = response.data
+      })
+    },
+    store() {
+      this.loading = true
+      this.accessToken = null
+      this.form.errors = []
+
+      axios
+        .post('/oauth/personal-access-tokens', this.form)
+        .then(response => {
+          this.loading = false
+          this.form.name = ''
+          this.form.errors = []
+
+          this.tokens.push(response.data.token)
+
+          this.showAccessToken(response.data.accessToken)
+        })
+        .catch(error => {
+          this.loading = false
+          if (typeof error.response.data === 'object') {
+            this.form.errors = _.flatten(_.toArray(error.response.data.errors))
+          } else {
+            this.error()
+          }
+        })
+    },
+    showAccessToken(accessToken) {
+      this.createTokenModalOpen = false
+      this.accessToken = accessToken
+      this.accessTokenModalOpen = true
+    },
+    showRevokeModal(token) {
+      this.tokenToRevoke = token
+      this.revokeTokenModalOpen = true
+    },
+    revoke() {
+      this.revokeTokenLoading = true
+
+      axios.delete(`/oauth/personal-access-tokens/${this.tokenToRevoke.id}`).then(response => {
+        this.revokeTokenLoading = false
+        this.revokeTokenModalOpen = false
+        this.tokenToRevoke = null
+        this.getTokens()
+      })
+    },
+    openCreateTokenModal() {
+      this.createTokenModalOpen = true
+    },
+    closeCreateTokenModal() {
+      this.createTokenModalOpen = false
+    },
+    closeAccessTokenModal() {
+      this.accessTokenModalOpen = false
+    },
+    closeRevokeTokenModal() {
+      this.revokeTokenModalOpen = false
+    },
+    clipboardSuccess() {
+      this.success('Copied to clipboard')
+    },
+    clipboardError() {
+      this.error('Could not copy to clipboard')
+    },
+    success(text = '') {
+      this.$notify({
+        title: 'Success',
+        text: text,
+        type: 'success',
+      })
+    },
+    error(text = 'An error has occurred, please try again later') {
+      this.$notify({
+        title: 'Error',
+        text: text,
+        type: 'error',
+      })
+    },
+  },
+}
+</script>

+ 2 - 12
resources/views/settings/show.blade.php

@@ -432,22 +432,12 @@
             <h2 class="text-3xl font-bold">
                 API
             </h2>
-            <p class="text-grey-500">Manage your API Token</p>
+            <p class="text-grey-500">Manage your API Access Tokens</p>
         </div>
 
         <div class="px-6 py-8 md:p-10 bg-white rounded-lg shadow mb-10">
 
-            <h3 class="font-bold text-xl">
-                Information
-            </h3>
-
-            <div class="mt-4 w-24 border-b-2 border-grey-200"></div>
-
-            <p class="mt-6">
-                Your API token can be used with the <a href="https://github.com/anonaddy/browser-extension" target="_blank" rel="nofollow noopener noreferrer" class="text-indigo-700">open-source</a> AnonAddy browser extension on <a href="https://addons.mozilla.org/en-GB/firefox/addon/anonaddy/" target="_blank" rel="nofollow noopener noreferrer" class="text-indigo-700">Firefox</a> or <a href="https://chrome.google.com/webstore/detail/anonaddy/iadbdpnoknmbdeolbapdackdcogdmjpe" target="_blank" rel="nofollow noopener noreferrer" class="text-indigo-700">Chrome / Brave</a> to generate UUID aliases. Simply paste the token generated below into the browser extension to get started. Your API token is secret and should be treated like your password.
-            </p>
-
-            <api-token initial-token="{{ $user->api_token }}" />
+            <passport-personal-access-tokens />
 
         </div>
 

+ 0 - 3
routes/web.php

@@ -86,7 +86,4 @@ Route::group([
     Route::post('/2fa/enable', 'TwoFactorAuthController@store')->name('settings.2fa_enable');
     Route::post('/2fa/regenerate', 'TwoFactorAuthController@update')->name('settings.2fa_regenerate');
     Route::post('/2fa/disable', 'TwoFactorAuthController@destroy')->name('settings.2fa_disable');
-
-    Route::post('/api-token', 'Api\ApiTokenController@update')->name('api_token.update');
-    Route::delete('/api-token', 'Api\ApiTokenController@destroy')->name('api_token.destroy');
 });

+ 42 - 18
tests/Feature/Api/ApiTokensTest.php

@@ -4,7 +4,9 @@ namespace Tests\Feature\Api;
 
 use App\User;
 use Illuminate\Foundation\Testing\RefreshDatabase;
-use Illuminate\Support\Str;
+use Illuminate\Support\Facades\DB;
+use Laravel\Passport\ClientRepository;
+use Laravel\Passport\Passport;
 use Tests\TestCase;
 
 class ApiTokensTest extends TestCase
@@ -18,38 +20,60 @@ class ApiTokensTest extends TestCase
         parent::setUp();
 
         $this->user = factory(User::class)->create();
-        $this->actingAs($this->user);
+        Passport::actingAs($this->user, []);
         $this->user->recipients()->save($this->user->defaultRecipient);
+
+        $clientRepository = new ClientRepository();
+        $client = $clientRepository->createPersonalAccessClient(
+            null,
+            'Test Personal Access Client',
+            config('app.url')
+        );
+        DB::table('oauth_personal_access_clients')->insert([
+            'client_id' => $client->id,
+            'created_at' => now(),
+            'updated_at' => now(),
+        ]);
     }
 
     /** @test */
-    public function user_can_rotate_api_token()
+    public function user_can_generate_api_token()
     {
-        $this->assertNull($this->user->api_token);
-
-        $response = $this->json('POST', '/settings/api-token', []);
+        $response = $this->post('/oauth/personal-access-tokens', [
+            'name' => 'New'
+        ]);
 
         $response->assertStatus(200);
 
-        $this->assertNotNull($response->getData()->token);
-        $this->assertNotNull($this->user->refresh()->api_token);
+        $this->assertNotNull($response->getData()->accessToken);
+        $this->assertDatabaseHas('oauth_access_tokens', [
+            'name' => 'New',
+            'user_id' => $this->user->id
+        ]);
     }
 
     /** @test */
     public function user_can_revoke_api_token()
     {
-        $token = Str::random(60);
-
-        $this->user->forceFill([
-            'api_token' => hash('sha256', $token),
-        ])->save();
-
-        $this->assertNotNull($this->user->refresh()->api_token);
-
-        $response = $this->json('DELETE', '/settings/api-token');
+        DB::table('oauth_access_tokens')->insert([
+            'id' => '1830c31e8e17dc4e871aa21ebe82e6cbfdd0d5781bec42631dd381119f355a911075f7e1a3dc2240',
+            'name' => 'New',
+            'user_id' => $this->user->id,
+            'revoked' => false,
+            'client_id' => 1,
+            'created_at' => now(),
+            'updated_at' => now(),
+        ]);
+
+        $response = $this->delete('/oauth/personal-access-tokens/1830c31e8e17dc4e871aa21ebe82e6cbfdd0d5781bec42631dd381119f355a911075f7e1a3dc2240');
 
         $response->assertStatus(204);
 
-        $this->assertNull($this->user->refresh()->api_token);
+        $this->assertDatabaseMissing('oauth_access_tokens', [
+            'name' => 'New',
+            'user_id' => $this->user->id,
+            'id' => '1830c31e8e17dc4e871aa21ebe82e6cbfdd0d5781bec42631dd381119f355a911075f7e1a3dc2240',
+            'revoke' => true
+        ]);
     }
 }

+ 0 - 1
tests/Feature/RegistrationTest.php

@@ -50,7 +50,6 @@ class RegistrationTest extends TestCase
     /** @test */
     public function user_can_verify_email_successfully()
     {
-        $this->withoutExceptionHandling();
         $user = factory(User::class)->create();
         $user->email_verified_at = null;
         $user->save();