├── .gitattributes ├── .gitignore ├── README.md ├── app ├── Http │ ├── Controllers │ │ ├── Auth │ │ │ └── AuthController.php │ │ └── UserController.php │ ├── Kernel.php │ ├── Requests │ │ └── RegisterFormRequest.php │ └── routes.php └── Models │ └── User.php ├── composer.json ├── config ├── app.php ├── auth.php └── jwt.php ├── gulpfile.js ├── package.json └── resources ├── .babelrc ├── .gitignore ├── README.md ├── assets ├── components │ ├── App.vue │ ├── Dashboard.vue │ ├── Home.vue │ ├── Register.vue │ └── Signin.vue └── js │ ├── app.js │ └── auth.js ├── index.html ├── package.json ├── views └── welcome.blade.php └── webpack.config.js /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto 2 | *.css linguist-vendored 3 | *.scss linguist-vendored 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /vendor 2 | /node_modules 3 | /public/storage 4 | Homestead.yaml 5 | Homestead.json 6 | .env 7 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # laravel-vuejs-jwt-auth 2 | Using Laravel to build JSON Web Token based authentication with a Vue.js 2.x user interface 3 | 4 | http://jimfrenette.com/2016/11/laravel-vuejs2-jwt-auth/ 5 | 6 | Versions used for this build 7 | 8 | * Laravel 5.2 9 | * JWT Auth v0.5.9 10 | * Nodejs v6.9.4 11 | * NPM v3.10.10 12 | * Vue v2.1.1 13 | * Vue-cli v2.8.1 14 | * Vue-resource v1.2.0 15 | * Vue-router v2.1.0 16 | * Webpack v2.2.0 17 | 18 | Refer to the resources/package.json for more info 19 | 20 | ## TODO 21 | 22 | ### Refresh Tokens 23 | 24 | The current user's access token is refreshed. This case can happen in the following conditions: 25 | 26 | * The access token expires: this is a common situation. The refresh token is used to get a new valid set of tokens. 27 | * The user changes his password: Server issues new refresh tokens and renders the old tokens expired. 28 | * The user re-authenticates: some actions require that the user's credentials are recently issued; such actions include deleting an account, setting a primary email address, and changing a password. Instead of signing out the user and then signing in the user again, get new credentials from the user, and pass the new credentials to the reauthenticate method of the User object. 29 | -------------------------------------------------------------------------------- /app/Http/Controllers/Auth/AuthController.php: -------------------------------------------------------------------------------- 1 | $request->json('name'), 19 | 'email' => $request->json('email'), 20 | 'password' => bcrypt($request->json('password')), 21 | ]); 22 | } 23 | 24 | public function signin(Request $request) 25 | { 26 | try { 27 | $token = JWTAuth::attempt($request->only('email', 'password'), [ 28 | 'exp' => Carbon::now()->addWeek()->timestamp, 29 | ]); 30 | } catch (JWTException $e) { 31 | return response()->json([ 32 | 'error' => 'Could not authenticate', 33 | ], 500); 34 | } 35 | 36 | if (!$token) { 37 | return response()->json([ 38 | 'error' => 'Could not authenticate', 39 | ], 401); 40 | } else { 41 | $data = []; 42 | $meta = []; 43 | 44 | $data['name'] = $request->user()->name; 45 | $meta['token'] = $token; 46 | 47 | return response()->json([ 48 | 'data' => $data, 49 | 'meta' => $meta 50 | ]); 51 | } 52 | } 53 | } -------------------------------------------------------------------------------- /app/Http/Controllers/UserController.php: -------------------------------------------------------------------------------- 1 | user()->name; 15 | $data['email'] = $request->user()->email; 16 | return response()->json([ 17 | 'data' => $data, 18 | ]); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /app/Http/Kernel.php: -------------------------------------------------------------------------------- 1 | [ 27 | \App\Http\Middleware\EncryptCookies::class, 28 | \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class, 29 | \Illuminate\Session\Middleware\StartSession::class, 30 | \Illuminate\View\Middleware\ShareErrorsFromSession::class, 31 | \App\Http\Middleware\VerifyCsrfToken::class, 32 | ], 33 | 34 | 'api' => [ 35 | 'throttle:60,1', 36 | ], 37 | ]; 38 | 39 | /** 40 | * The application's route middleware. 41 | * 42 | * These middleware may be assigned to groups or used individually. 43 | * 44 | * @var array 45 | */ 46 | protected $routeMiddleware = [ 47 | 'auth' => \App\Http\Middleware\Authenticate::class, 48 | 'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class, 49 | 'can' => \Illuminate\Foundation\Http\Middleware\Authorize::class, 50 | 'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class, 51 | 'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class, 52 | 'jwt.auth' => \Tymon\JWTAuth\Middleware\GetUserFromToken::class, 53 | ]; 54 | } 55 | -------------------------------------------------------------------------------- /app/Http/Requests/RegisterFormRequest.php: -------------------------------------------------------------------------------- 1 | 'required', 28 | 'email' => 'required|email|unique:users', 29 | 'password' => 'required', 30 | ]; 31 | } 32 | } -------------------------------------------------------------------------------- /app/Http/routes.php: -------------------------------------------------------------------------------- 1 | ['api']], function () { 19 | Route::post('/api/register', [ 20 | 'uses' => 'Auth\AuthController@register', 21 | ]); 22 | 23 | Route::post('/api/signin', [ 24 | 'uses' => 'Auth\AuthController@signin', 25 | ]); 26 | 27 | Route::group(['middleware' => 'jwt.auth'], function () { 28 | Route::get('/api/user', [ 29 | 'uses' => 'UserController@index', 30 | ]); 31 | }); 32 | 33 | }); 34 | -------------------------------------------------------------------------------- /app/Models/User.php: -------------------------------------------------------------------------------- 1 | =5.5.9", 9 | "laravel/framework": "5.2.*", 10 | "tymon/jwt-auth": "^0.5.9" 11 | }, 12 | "require-dev": { 13 | "fzaninotto/faker": "~1.4", 14 | "mockery/mockery": "0.9.*", 15 | "phpunit/phpunit": "~4.0", 16 | "symfony/css-selector": "2.8.*|3.0.*", 17 | "symfony/dom-crawler": "2.8.*|3.0.*" 18 | }, 19 | "autoload": { 20 | "classmap": [ 21 | "database" 22 | ], 23 | "psr-4": { 24 | "App\\": "app/" 25 | } 26 | }, 27 | "autoload-dev": { 28 | "classmap": [ 29 | "tests/TestCase.php" 30 | ] 31 | }, 32 | "scripts": { 33 | "post-root-package-install": [ 34 | "php -r \"copy('.env.example', '.env');\"" 35 | ], 36 | "post-create-project-cmd": [ 37 | "php artisan key:generate" 38 | ], 39 | "post-install-cmd": [ 40 | "Illuminate\\Foundation\\ComposerScripts::postInstall", 41 | "php artisan optimize" 42 | ], 43 | "post-update-cmd": [ 44 | "Illuminate\\Foundation\\ComposerScripts::postUpdate", 45 | "php artisan optimize" 46 | ] 47 | }, 48 | "config": { 49 | "preferred-install": "dist" 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /config/app.php: -------------------------------------------------------------------------------- 1 | env('APP_ENV', 'production'), 17 | 18 | /* 19 | |-------------------------------------------------------------------------- 20 | | Application Debug Mode 21 | |-------------------------------------------------------------------------- 22 | | 23 | | When your application is in debug mode, detailed error messages with 24 | | stack traces will be shown on every error that occurs within your 25 | | application. If disabled, a simple generic error page is shown. 26 | | 27 | */ 28 | 29 | 'debug' => env('APP_DEBUG', false), 30 | 31 | /* 32 | |-------------------------------------------------------------------------- 33 | | Application URL 34 | |-------------------------------------------------------------------------- 35 | | 36 | | This URL is used by the console to properly generate URLs when using 37 | | the Artisan command line tool. You should set this to the root of 38 | | your application so that it is used when running Artisan tasks. 39 | | 40 | */ 41 | 42 | 'url' => env('APP_URL', 'http://localhost'), 43 | 44 | /* 45 | |-------------------------------------------------------------------------- 46 | | Application Timezone 47 | |-------------------------------------------------------------------------- 48 | | 49 | | Here you may specify the default timezone for your application, which 50 | | will be used by the PHP date and date-time functions. We have gone 51 | | ahead and set this to a sensible default for you out of the box. 52 | | 53 | */ 54 | 55 | 'timezone' => 'UTC', 56 | 57 | /* 58 | |-------------------------------------------------------------------------- 59 | | Application Locale Configuration 60 | |-------------------------------------------------------------------------- 61 | | 62 | | The application locale determines the default locale that will be used 63 | | by the translation service provider. You are free to set this value 64 | | to any of the locales which will be supported by the application. 65 | | 66 | */ 67 | 68 | 'locale' => 'en', 69 | 70 | /* 71 | |-------------------------------------------------------------------------- 72 | | Application Fallback Locale 73 | |-------------------------------------------------------------------------- 74 | | 75 | | The fallback locale determines the locale to use when the current one 76 | | is not available. You may change the value to correspond to any of 77 | | the language folders that are provided through your application. 78 | | 79 | */ 80 | 81 | 'fallback_locale' => 'en', 82 | 83 | /* 84 | |-------------------------------------------------------------------------- 85 | | Encryption Key 86 | |-------------------------------------------------------------------------- 87 | | 88 | | This key is used by the Illuminate encrypter service and should be set 89 | | to a random, 32 character string, otherwise these encrypted strings 90 | | will not be safe. Please do this before deploying an application! 91 | | 92 | */ 93 | 94 | 'key' => env('APP_KEY'), 95 | 96 | 'cipher' => 'AES-256-CBC', 97 | 98 | /* 99 | |-------------------------------------------------------------------------- 100 | | Logging Configuration 101 | |-------------------------------------------------------------------------- 102 | | 103 | | Here you may configure the log settings for your application. Out of 104 | | the box, Laravel uses the Monolog PHP logging library. This gives 105 | | you a variety of powerful log handlers / formatters to utilize. 106 | | 107 | | Available Settings: "single", "daily", "syslog", "errorlog" 108 | | 109 | */ 110 | 111 | 'log' => env('APP_LOG', 'single'), 112 | 113 | /* 114 | |-------------------------------------------------------------------------- 115 | | Autoloaded Service Providers 116 | |-------------------------------------------------------------------------- 117 | | 118 | | The service providers listed here will be automatically loaded on the 119 | | request to your application. Feel free to add your own services to 120 | | this array to grant expanded functionality to your applications. 121 | | 122 | */ 123 | 124 | 'providers' => [ 125 | 126 | /* 127 | * Laravel Framework Service Providers... 128 | */ 129 | Illuminate\Auth\AuthServiceProvider::class, 130 | Illuminate\Broadcasting\BroadcastServiceProvider::class, 131 | Illuminate\Bus\BusServiceProvider::class, 132 | Illuminate\Cache\CacheServiceProvider::class, 133 | Illuminate\Foundation\Providers\ConsoleSupportServiceProvider::class, 134 | Illuminate\Cookie\CookieServiceProvider::class, 135 | Illuminate\Database\DatabaseServiceProvider::class, 136 | Illuminate\Encryption\EncryptionServiceProvider::class, 137 | Illuminate\Filesystem\FilesystemServiceProvider::class, 138 | Illuminate\Foundation\Providers\FoundationServiceProvider::class, 139 | Illuminate\Hashing\HashServiceProvider::class, 140 | Illuminate\Mail\MailServiceProvider::class, 141 | Illuminate\Pagination\PaginationServiceProvider::class, 142 | Illuminate\Pipeline\PipelineServiceProvider::class, 143 | Illuminate\Queue\QueueServiceProvider::class, 144 | Illuminate\Redis\RedisServiceProvider::class, 145 | Illuminate\Auth\Passwords\PasswordResetServiceProvider::class, 146 | Illuminate\Session\SessionServiceProvider::class, 147 | Illuminate\Translation\TranslationServiceProvider::class, 148 | Illuminate\Validation\ValidationServiceProvider::class, 149 | Illuminate\View\ViewServiceProvider::class, 150 | 151 | /* 152 | * Application Service Providers... 153 | */ 154 | App\Providers\AppServiceProvider::class, 155 | App\Providers\AuthServiceProvider::class, 156 | App\Providers\EventServiceProvider::class, 157 | App\Providers\RouteServiceProvider::class, 158 | 159 | Tymon\JWTAuth\Providers\JWTAuthServiceProvider::class, 160 | ], 161 | 162 | /* 163 | |-------------------------------------------------------------------------- 164 | | Class Aliases 165 | |-------------------------------------------------------------------------- 166 | | 167 | | This array of class aliases will be registered when this application 168 | | is started. However, feel free to register as many as you wish as 169 | | the aliases are "lazy" loaded so they don't hinder performance. 170 | | 171 | */ 172 | 173 | 'aliases' => [ 174 | 175 | 'App' => Illuminate\Support\Facades\App::class, 176 | 'Artisan' => Illuminate\Support\Facades\Artisan::class, 177 | 'Auth' => Illuminate\Support\Facades\Auth::class, 178 | 'Blade' => Illuminate\Support\Facades\Blade::class, 179 | 'Cache' => Illuminate\Support\Facades\Cache::class, 180 | 'Config' => Illuminate\Support\Facades\Config::class, 181 | 'Cookie' => Illuminate\Support\Facades\Cookie::class, 182 | 'Crypt' => Illuminate\Support\Facades\Crypt::class, 183 | 'DB' => Illuminate\Support\Facades\DB::class, 184 | 'Eloquent' => Illuminate\Database\Eloquent\Model::class, 185 | 'Event' => Illuminate\Support\Facades\Event::class, 186 | 'File' => Illuminate\Support\Facades\File::class, 187 | 'Gate' => Illuminate\Support\Facades\Gate::class, 188 | 'Hash' => Illuminate\Support\Facades\Hash::class, 189 | 'Lang' => Illuminate\Support\Facades\Lang::class, 190 | 'Log' => Illuminate\Support\Facades\Log::class, 191 | 'Mail' => Illuminate\Support\Facades\Mail::class, 192 | 'Password' => Illuminate\Support\Facades\Password::class, 193 | 'Queue' => Illuminate\Support\Facades\Queue::class, 194 | 'Redirect' => Illuminate\Support\Facades\Redirect::class, 195 | 'Redis' => Illuminate\Support\Facades\Redis::class, 196 | 'Request' => Illuminate\Support\Facades\Request::class, 197 | 'Response' => Illuminate\Support\Facades\Response::class, 198 | 'Route' => Illuminate\Support\Facades\Route::class, 199 | 'Schema' => Illuminate\Support\Facades\Schema::class, 200 | 'Session' => Illuminate\Support\Facades\Session::class, 201 | 'Storage' => Illuminate\Support\Facades\Storage::class, 202 | 'URL' => Illuminate\Support\Facades\URL::class, 203 | 'Validator' => Illuminate\Support\Facades\Validator::class, 204 | 'View' => Illuminate\Support\Facades\View::class, 205 | 206 | 'JWTAuth' => Tymon\JWTAuth\Facades\JWTAuth::class, 207 | ], 208 | 209 | ]; 210 | -------------------------------------------------------------------------------- /config/auth.php: -------------------------------------------------------------------------------- 1 | [ 17 | 'guard' => 'web', 18 | 'passwords' => 'users', 19 | ], 20 | 21 | /* 22 | |-------------------------------------------------------------------------- 23 | | Authentication Guards 24 | |-------------------------------------------------------------------------- 25 | | 26 | | Next, you may define every authentication guard for your application. 27 | | Of course, a great default configuration has been defined for you 28 | | here which uses session storage and the Eloquent user provider. 29 | | 30 | | All authentication drivers have a user provider. This defines how the 31 | | users are actually retrieved out of your database or other storage 32 | | mechanisms used by this application to persist your user's data. 33 | | 34 | | Supported: "session", "token" 35 | | 36 | */ 37 | 38 | 'guards' => [ 39 | 'web' => [ 40 | 'driver' => 'session', 41 | 'provider' => 'users', 42 | ], 43 | 44 | 'api' => [ 45 | 'driver' => 'token', 46 | 'provider' => 'users', 47 | ], 48 | ], 49 | 50 | /* 51 | |-------------------------------------------------------------------------- 52 | | User Providers 53 | |-------------------------------------------------------------------------- 54 | | 55 | | All authentication drivers have a user provider. This defines how the 56 | | users are actually retrieved out of your database or other storage 57 | | mechanisms used by this application to persist your user's data. 58 | | 59 | | If you have multiple user tables or models you may configure multiple 60 | | sources which represent each model / table. These sources may then 61 | | be assigned to any extra authentication guards you have defined. 62 | | 63 | | Supported: "database", "eloquent" 64 | | 65 | */ 66 | 67 | 'providers' => [ 68 | 'users' => [ 69 | 'driver' => 'eloquent', 70 | 'model' => App\Models\User::class, 71 | ], 72 | 73 | // 'users' => [ 74 | // 'driver' => 'database', 75 | // 'table' => 'users', 76 | // ], 77 | ], 78 | 79 | /* 80 | |-------------------------------------------------------------------------- 81 | | Resetting Passwords 82 | |-------------------------------------------------------------------------- 83 | | 84 | | Here you may set the options for resetting passwords including the view 85 | | that is your password reset e-mail. You may also set the name of the 86 | | table that maintains all of the reset tokens for your application. 87 | | 88 | | You may specify multiple password reset configurations if you have more 89 | | than one user table or model in the application and you want to have 90 | | separate password reset settings based on the specific user types. 91 | | 92 | | The expire time is the number of minutes that the reset token should be 93 | | considered valid. This security feature keeps tokens short-lived so 94 | | they have less time to be guessed. You may change this as needed. 95 | | 96 | */ 97 | 98 | 'passwords' => [ 99 | 'users' => [ 100 | 'provider' => 'users', 101 | 'email' => 'auth.emails.password', 102 | 'table' => 'password_resets', 103 | 'expire' => 60, 104 | ], 105 | ], 106 | 107 | ]; 108 | -------------------------------------------------------------------------------- /config/jwt.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | return [ 13 | 14 | /* 15 | |-------------------------------------------------------------------------- 16 | | JWT Authentication Secret 17 | |-------------------------------------------------------------------------- 18 | | 19 | | Don't forget to set this, as it will be used to sign your tokens. 20 | | A helper command is provided for this: `php artisan jwt:generate` 21 | | 22 | */ 23 | 24 | 'secret' => env('JWT_SECRET', '0KaGvrtTvnZmP7Hydt832K8QWJDJsnLl'), 25 | 26 | /* 27 | |-------------------------------------------------------------------------- 28 | | JWT time to live 29 | |-------------------------------------------------------------------------- 30 | | 31 | | Specify the length of time (in minutes) that the token will be valid for. 32 | | Defaults to 1 hour 33 | | 34 | */ 35 | 36 | 'ttl' => 60, 37 | 38 | /* 39 | |-------------------------------------------------------------------------- 40 | | Refresh time to live 41 | |-------------------------------------------------------------------------- 42 | | 43 | | Specify the length of time (in minutes) that the token can be refreshed 44 | | within. I.E. The user can refresh their token within a 2 week window of 45 | | the original token being created until they must re-authenticate. 46 | | Defaults to 2 weeks 47 | | 48 | */ 49 | 50 | 'refresh_ttl' => 20160, 51 | 52 | /* 53 | |-------------------------------------------------------------------------- 54 | | JWT hashing algorithm 55 | |-------------------------------------------------------------------------- 56 | | 57 | | Specify the hashing algorithm that will be used to sign the token. 58 | | 59 | | See here: https://github.com/namshi/jose/tree/2.2.0/src/Namshi/JOSE/Signer 60 | | for possible values 61 | | 62 | */ 63 | 64 | 'algo' => 'HS256', 65 | 66 | /* 67 | |-------------------------------------------------------------------------- 68 | | User Model namespace 69 | |-------------------------------------------------------------------------- 70 | | 71 | | Specify the full namespace to your User model. 72 | | e.g. 'Acme\Entities\User' 73 | | 74 | */ 75 | 76 | 'user' => App\Models\User::class, 77 | 78 | /* 79 | |-------------------------------------------------------------------------- 80 | | User identifier 81 | |-------------------------------------------------------------------------- 82 | | 83 | | Specify a unique property of the user that will be added as the 'sub' 84 | | claim of the token payload. 85 | | 86 | */ 87 | 88 | 'identifier' => 'id', 89 | 90 | /* 91 | |-------------------------------------------------------------------------- 92 | | Required Claims 93 | |-------------------------------------------------------------------------- 94 | | 95 | | Specify the required claims that must exist in any token. 96 | | A TokenInvalidException will be thrown if any of these claims are not 97 | | present in the payload. 98 | | 99 | */ 100 | 101 | 'required_claims' => ['iss', 'iat', 'exp', 'nbf', 'sub', 'jti'], 102 | 103 | /* 104 | |-------------------------------------------------------------------------- 105 | | Blacklist Enabled 106 | |-------------------------------------------------------------------------- 107 | | 108 | | In order to invalidate tokens, you must have the the blacklist enabled. 109 | | If you do not want or need this functionality, then set this to false. 110 | | 111 | */ 112 | 113 | 'blacklist_enabled' => env('JWT_BLACKLIST_ENABLED', true), 114 | 115 | /* 116 | |-------------------------------------------------------------------------- 117 | | Providers 118 | |-------------------------------------------------------------------------- 119 | | 120 | | Specify the various providers used throughout the package. 121 | | 122 | */ 123 | 124 | 'providers' => [ 125 | 126 | /* 127 | |-------------------------------------------------------------------------- 128 | | User Provider 129 | |-------------------------------------------------------------------------- 130 | | 131 | | Specify the provider that is used to find the user based 132 | | on the subject claim 133 | | 134 | */ 135 | 136 | 'user' => 'Tymon\JWTAuth\Providers\User\EloquentUserAdapter', 137 | 138 | /* 139 | |-------------------------------------------------------------------------- 140 | | JWT Provider 141 | |-------------------------------------------------------------------------- 142 | | 143 | | Specify the provider that is used to create and decode the tokens. 144 | | 145 | */ 146 | 147 | 'jwt' => 'Tymon\JWTAuth\Providers\JWT\NamshiAdapter', 148 | 149 | /* 150 | |-------------------------------------------------------------------------- 151 | | Authentication Provider 152 | |-------------------------------------------------------------------------- 153 | | 154 | | Specify the provider that is used to authenticate users. 155 | | 156 | */ 157 | 158 | 'auth' => 'Tymon\JWTAuth\Providers\Auth\IlluminateAuthAdapter', 159 | 160 | /* 161 | |-------------------------------------------------------------------------- 162 | | Storage Provider 163 | |-------------------------------------------------------------------------- 164 | | 165 | | Specify the provider that is used to store tokens in the blacklist 166 | | 167 | */ 168 | 169 | 'storage' => 'Tymon\JWTAuth\Providers\Storage\IlluminateCacheAdapter', 170 | 171 | ], 172 | 173 | ]; 174 | -------------------------------------------------------------------------------- /gulpfile.js: -------------------------------------------------------------------------------- 1 | var elixir = require('laravel-elixir'); 2 | 3 | /* 4 | |-------------------------------------------------------------------------- 5 | | Elixir Asset Management 6 | |-------------------------------------------------------------------------- 7 | | 8 | | Elixir provides a clean, fluent API for defining some basic Gulp tasks 9 | | for your Laravel application. By default, we are compiling the Sass 10 | | file for our application, as well as publishing vendor resources. 11 | | 12 | */ 13 | 14 | elixir(function(mix) { 15 | //mix.webpack('app.js'); 16 | mix.browserSync( 17 | { 18 | proxy: "laravel.dev:8080", 19 | logConnections : false, 20 | reloadOnRestart : false, 21 | notify : false 22 | }); 23 | //mix.sass('app.scss'); 24 | }); 25 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "scripts": { 4 | "prod": "gulp --production", 5 | "dev": "gulp watch" 6 | }, 7 | "devDependencies": { 8 | "gulp": "^3.9.1", 9 | "laravel-elixir": "^5.0.0", 10 | "bootstrap-sass": "^3.3.0" 11 | } 12 | } -------------------------------------------------------------------------------- /resources/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | ["es2015", { "modules": false }] 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /resources/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules/ 3 | dist/ 4 | npm-debug.log 5 | -------------------------------------------------------------------------------- /resources/README.md: -------------------------------------------------------------------------------- 1 | # resources 2 | 3 | > A Vue.js project 4 | 5 | ## Build Setup 6 | 7 | ``` bash 8 | # install dependencies 9 | npm install 10 | 11 | # serve with hot reload at localhost:3000 12 | npm run dev 13 | 14 | # build for production with minification 15 | npm run build 16 | ``` 17 | 18 | For detailed explanation on how things work, consult the [docs for vue-loader](http://vuejs.github.io/vue-loader). 19 | -------------------------------------------------------------------------------- /resources/assets/components/App.vue: -------------------------------------------------------------------------------- 1 | 29 | 30 | 51 | -------------------------------------------------------------------------------- /resources/assets/components/Dashboard.vue: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /resources/assets/components/Home.vue: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /resources/assets/components/Register.vue: -------------------------------------------------------------------------------- 1 | 29 | 30 | -------------------------------------------------------------------------------- /resources/assets/components/Signin.vue: -------------------------------------------------------------------------------- 1 | 19 | -------------------------------------------------------------------------------- /resources/assets/js/app.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue'; 2 | import VueRouter from 'vue-router'; 3 | import VueResource from 'vue-resource'; 4 | import App from '../components/App.vue'; 5 | import Dashboard from '../components/Dashboard.vue'; 6 | import Home from '../components/Home.vue'; 7 | import Register from '../components/Register.vue'; 8 | import Signin from '../components/Signin.vue'; 9 | 10 | Vue.use(VueRouter); 11 | Vue.use(VueResource); 12 | 13 | Vue.http.headers.common['X-CSRF-TOKEN'] = document.getElementsByName('csrf-token')[0].getAttribute('content'); 14 | Vue.http.headers.common['Authorization'] = 'Bearer ' + localStorage.getItem('id_token'); 15 | Vue.http.options.root = 'http://laravel.dev:8080'; 16 | 17 | export default Vue; 18 | 19 | export var router = new VueRouter({ 20 | routes: [ 21 | { 22 | path: '/', 23 | name: 'home', 24 | component: Home 25 | }, 26 | { 27 | path: '/dashboard', 28 | name: 'dashboard', 29 | component: Dashboard 30 | }, 31 | { 32 | path: '/register', 33 | name: 'register', 34 | component: Register 35 | }, 36 | { 37 | path: '/signin', 38 | name: 'signin', 39 | component: Signin 40 | } 41 | ] 42 | }); 43 | 44 | new Vue({ 45 | el: '#app', 46 | router: router, 47 | render: app => app(App) 48 | }); 49 | -------------------------------------------------------------------------------- /resources/assets/js/auth.js: -------------------------------------------------------------------------------- 1 | import Vue from './app.js'; 2 | import {router} from './app.js'; 3 | 4 | export default { 5 | user: { 6 | authenticated: false, 7 | profile: null 8 | }, 9 | check() { 10 | let token = localStorage.getItem('id_token') 11 | if (token !== null) { 12 | Vue.http.get( 13 | 'api/user?token=' + token, 14 | ).then(response => { 15 | this.user.authenticated = true 16 | this.user.profile = response.data.data 17 | }) 18 | } 19 | }, 20 | register(context, name, email, password) { 21 | Vue.http.post( 22 | 'api/register', 23 | { 24 | name: name, 25 | email: email, 26 | password: password 27 | } 28 | ).then(response => { 29 | context.success = true 30 | }, response => { 31 | context.response = response.data 32 | context.error = true 33 | }) 34 | }, 35 | signin(context, email, password) { 36 | Vue.http.post( 37 | 'api/signin', 38 | { 39 | email: email, 40 | password: password 41 | } 42 | ).then(response => { 43 | context.error = false 44 | localStorage.setItem('id_token', response.data.meta.token) 45 | Vue.http.headers.common['Authorization'] = 'Bearer ' + localStorage.getItem('id_token') 46 | 47 | this.user.authenticated = true 48 | this.user.profile = response.data.data 49 | 50 | router.push({ 51 | name: 'dashboard' 52 | }) 53 | }, response => { 54 | context.error = true 55 | }) 56 | }, 57 | signout() { 58 | localStorage.removeItem('id_token') 59 | this.user.authenticated = false 60 | this.user.profile = null 61 | 62 | router.push({ 63 | name: 'home' 64 | }) 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /resources/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Laravel 7 | 8 | 9 | 10 | 11 | 12 |
13 |
14 |
15 | 16 | 17 | -------------------------------------------------------------------------------- /resources/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "resources", 3 | "description": "A Vue.js project", 4 | "author": "jimfrenette.com", 5 | "private": true, 6 | "scripts": { 7 | "dev": "cross-env NODE_ENV=development webpack-dev-server --port 3000 --open --inline --hot", 8 | "build": "cross-env NODE_ENV=production webpack --progress --hide-modules" 9 | }, 10 | "dependencies": { 11 | "vue": "^2.1.1" 12 | }, 13 | "devDependencies": { 14 | "babel-core": "^6.0.0", 15 | "babel-loader": "^6.0.0", 16 | "babel-preset-es2015": "^6.0.0", 17 | "cross-env": "^3.0.0", 18 | "css-loader": "^0.25.0", 19 | "file-loader": "^0.9.0", 20 | "vue-loader": "^10.0.0", 21 | "vue-resource": "^1.2.0", 22 | "vue-router": "^2.1.0", 23 | "vue-template-compiler": "^2.1.0", 24 | "webpack": "^2.2.0", 25 | "webpack-dev-server": "^2.2.0" 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /resources/views/welcome.blade.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Laravel 7 | 8 | 9 | 10 | 11 | 12 |
13 |
14 |
15 | 16 | 17 | -------------------------------------------------------------------------------- /resources/webpack.config.js: -------------------------------------------------------------------------------- 1 | var path = require('path') 2 | var webpack = require('webpack') 3 | 4 | module.exports = { 5 | entry: './assets/js/app.js', 6 | output: { 7 | path: path.resolve(__dirname, '../public/js'), 8 | publicPath: '/js/', 9 | filename: 'app.js' 10 | }, 11 | module: { 12 | rules: [ 13 | { 14 | test: /\.vue$/, 15 | loader: 'vue-loader', 16 | options: { 17 | // vue-loader options go here 18 | } 19 | }, 20 | { 21 | test: /\.js$/, 22 | loader: 'babel-loader', 23 | exclude: /node_modules/ 24 | }, 25 | { 26 | test: /\.(png|jpg|gif|svg)$/, 27 | loader: 'file-loader', 28 | options: { 29 | name: '[name].[ext]?[hash]' 30 | } 31 | } 32 | ] 33 | }, 34 | resolve: { 35 | alias: { 36 | 'vue$': 'vue/dist/vue.common.js' 37 | } 38 | }, 39 | devServer: { 40 | historyApiFallback: true, 41 | noInfo: true 42 | }, 43 | devtool: '#eval-source-map' 44 | } 45 | 46 | if (process.env.NODE_ENV === 'production') { 47 | module.exports.devtool = '#source-map' 48 | // http://vue-loader.vuejs.org/en/workflow/production.html 49 | module.exports.plugins = (module.exports.plugins || []).concat([ 50 | new webpack.DefinePlugin({ 51 | 'process.env': { 52 | NODE_ENV: '"production"' 53 | } 54 | }), 55 | new webpack.optimize.UglifyJsPlugin({ 56 | sourceMap: true, 57 | compress: { 58 | warnings: false 59 | } 60 | }), 61 | new webpack.LoaderOptionsPlugin({ 62 | minimize: true 63 | }) 64 | ]) 65 | } 66 | --------------------------------------------------------------------------------