├── .env.example
├── .gitignore
├── app
├── Author.php
├── Console
│ ├── Commands
│ │ └── .gitkeep
│ └── Kernel.php
├── Events
│ ├── Event.php
│ └── ExampleEvent.php
├── Exceptions
│ └── Handler.php
├── Http
│ ├── Controllers
│ │ ├── AuthorController.php
│ │ ├── Controller.php
│ │ └── ExampleController.php
│ └── Middleware
│ │ ├── Auth0Middleware.php
│ │ ├── Authenticate.php
│ │ └── ExampleMiddleware.php
├── Jobs
│ ├── ExampleJob.php
│ └── Job.php
├── Listeners
│ └── ExampleListener.php
├── Providers
│ ├── AppServiceProvider.php
│ ├── AuthServiceProvider.php
│ └── EventServiceProvider.php
└── User.php
├── artisan
├── bootstrap
└── app.php
├── composer.json
├── composer.lock
├── database
├── factories
│ └── ModelFactory.php
├── migrations
│ ├── .gitkeep
│ └── 2017_12_18_203510_create_authors_table.php
└── seeds
│ └── DatabaseSeeder.php
├── phpunit.xml
├── public
├── .htaccess
└── index.php
├── readme.md
├── resources
└── views
│ └── .gitkeep
├── routes
└── web.php
├── storage
├── app
│ └── .gitignore
├── framework
│ ├── cache
│ │ └── .gitignore
│ └── views
│ │ └── .gitignore
└── logs
│ └── .gitignore
└── tests
├── ExampleTest.php
└── TestCase.php
/.env.example:
--------------------------------------------------------------------------------
1 | APP_ENV=local
2 | APP_DEBUG=true
3 | APP_KEY=
4 | APP_TIMEZONE=UTC
5 |
6 | AUTH0_DOMAIN=https://your-domain.auth0.com/
7 | AUTH0_AUD=https://authorsapi.com
8 |
9 | DB_CONNECTION=mysql
10 | DB_HOST=127.0.0.1
11 | DB_PORT=3306
12 | DB_DATABASE=homestead
13 | DB_USERNAME=homestead
14 | DB_PASSWORD=secret
15 |
16 | CACHE_DRIVER=file
17 | QUEUE_DRIVER=sync
18 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | /vendor
2 | /.idea
3 | Homestead.json
4 | Homestead.yaml
5 | .env
6 |
--------------------------------------------------------------------------------
/app/Author.php:
--------------------------------------------------------------------------------
1 | json(Author::all());
14 | }
15 |
16 | public function showOneAuthor($id)
17 | {
18 | return response()->json(Author::find($id));
19 | }
20 |
21 | public function create(Request $request)
22 | {
23 | $this->validate($request, [
24 | 'name' => 'required',
25 | 'email' => 'required|email|unique:authors',
26 | 'location' => 'required|alpha'
27 | ]);
28 |
29 | $author = Author::create($request->all());
30 |
31 | return response()->json($author, 201);
32 | }
33 |
34 | public function update($id, Request $request)
35 | {
36 | $author = Author::findOrFail($id);
37 | $author->update($request->all());
38 |
39 | return response()->json($author, 200);
40 | }
41 |
42 | public function delete($id)
43 | {
44 | Author::findOrFail($id)->delete();
45 | return response('Deleted Successfully', 200);
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/app/Http/Controllers/Controller.php:
--------------------------------------------------------------------------------
1 | bearerToken();
24 |
25 | if(!$token) {
26 | return response()->json('No token provided', 401);
27 | }
28 |
29 | $this->validateAndDecode($token);
30 | $decodedToken = $this->validateAndDecode($token);
31 | if ($scopeRequired && !$this->tokenHasScope($decodedToken, $scopeRequired)) {
32 | return response()->json(['message' => 'Insufficient scope'], 403);
33 | }
34 | return $next($request);
35 | }
36 |
37 | public function validateAndDecode($token)
38 | {
39 | try {
40 | $jwksUri = env('AUTH0_DOMAIN') . '.well-known/jwks.json';
41 |
42 | $jwksFetcher = new JWKFetcher(null, [ 'base_uri' => $jwksUri ]);
43 | $signatureVerifier = new AsymmetricVerifier($jwksFetcher);
44 | $tokenVerifier = new TokenVerifier(env('AUTH0_DOMAIN'), env('AUTH0_AUD'), $signatureVerifier);
45 |
46 | return $tokenVerifier->verify($token);
47 | }
48 | catch(InvalidTokenException $e) {
49 | throw $e;
50 | };
51 | }
52 |
53 | /**
54 | * Check if a token has a specific scope.
55 | *
56 | * @param \stdClass $token - JWT access token to check.
57 | * @param string $scopeRequired - Scope to check for.
58 | *
59 | * @return bool
60 | */
61 | protected function tokenHasScope($token, $scopeRequired)
62 | {
63 | if (empty($token['scope'])) {
64 | return false;
65 | }
66 |
67 | $tokenScopes = explode(' ', $token['scope']);
68 |
69 | return in_array($scopeRequired, $tokenScopes);
70 | }
71 |
72 | }
--------------------------------------------------------------------------------
/app/Http/Middleware/Authenticate.php:
--------------------------------------------------------------------------------
1 | auth = $auth;
26 | }
27 |
28 | /**
29 | * Handle an incoming request.
30 | *
31 | * @param \Illuminate\Http\Request $request
32 | * @param \Closure $next
33 | * @param string|null $guard
34 | * @return mixed
35 | */
36 | public function handle($request, Closure $next, $guard = null)
37 | {
38 | if ($this->auth->guard($guard)->guest()) {
39 | return response('Unauthorized.', 401);
40 | }
41 |
42 | return $next($request);
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/app/Http/Middleware/ExampleMiddleware.php:
--------------------------------------------------------------------------------
1 | app['auth']->viaRequest('api', function ($request) {
34 | if ($request->input('api_token')) {
35 | return User::where('api_token', $request->input('api_token'))->first();
36 | }
37 | });
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/app/Providers/EventServiceProvider.php:
--------------------------------------------------------------------------------
1 | [
16 | 'App\Listeners\EventListener',
17 | ],
18 | ];
19 | }
20 |
--------------------------------------------------------------------------------
/app/User.php:
--------------------------------------------------------------------------------
1 | make(
32 | 'Illuminate\Contracts\Console\Kernel'
33 | );
34 |
35 | exit($kernel->handle(new ArgvInput, new ConsoleOutput));
36 |
--------------------------------------------------------------------------------
/bootstrap/app.php:
--------------------------------------------------------------------------------
1 | load();
7 | } catch (Dotenv\Exception\InvalidPathException $e) {
8 | //
9 | }
10 |
11 | /*
12 | |--------------------------------------------------------------------------
13 | | Create The Application
14 | |--------------------------------------------------------------------------
15 | |
16 | | Here we will load the environment and create the application instance
17 | | that serves as the central piece of this framework. We'll use this
18 | | application as an "IoC" container and router for this framework.
19 | |
20 | */
21 |
22 | $app = new Laravel\Lumen\Application(
23 | realpath(__DIR__.'/../')
24 | );
25 |
26 | $app->withFacades();
27 |
28 | $app->withEloquent();
29 |
30 | /*
31 | |--------------------------------------------------------------------------
32 | | Register Container Bindings
33 | |--------------------------------------------------------------------------
34 | |
35 | | Now we will register a few bindings in the service container. We will
36 | | register the exception handler and the console kernel. You may add
37 | | your own bindings here if you like or you can make another file.
38 | |
39 | */
40 |
41 | $app->singleton(
42 | Illuminate\Contracts\Debug\ExceptionHandler::class,
43 | App\Exceptions\Handler::class
44 | );
45 |
46 | $app->singleton(
47 | Illuminate\Contracts\Console\Kernel::class,
48 | App\Console\Kernel::class
49 | );
50 |
51 | /*
52 | |--------------------------------------------------------------------------
53 | | Register Middleware
54 | |--------------------------------------------------------------------------
55 | |
56 | | Next, we will register the middleware with the application. These can
57 | | be global middleware that run before and after each request into a
58 | | route or middleware that'll be assigned to some specific routes.
59 | |
60 | */
61 |
62 | // $app->middleware([
63 | // App\Http\Middleware\ExampleMiddleware::class
64 | // ]);
65 |
66 | // $app->routeMiddleware([
67 | // 'auth' => App\Http\Middleware\Authenticate::class,
68 | // ]);
69 |
70 | $app->routeMiddleware([
71 | 'auth' => App\Http\Middleware\Auth0Middleware::class,
72 | ]);
73 |
74 | /*
75 | |--------------------------------------------------------------------------
76 | | Register Service Providers
77 | |--------------------------------------------------------------------------
78 | |
79 | | Here we will register all of the application's service providers which
80 | | are used to bind services into the container. Service providers are
81 | | totally optional, so you are not required to uncomment this line.
82 | |
83 | */
84 |
85 | // $app->register(App\Providers\AppServiceProvider::class);
86 | // $app->register(App\Providers\AuthServiceProvider::class);
87 | // $app->register(App\Providers\EventServiceProvider::class);
88 |
89 | /*
90 | |--------------------------------------------------------------------------
91 | | Load The Application Routes
92 | |--------------------------------------------------------------------------
93 | |
94 | | Next we will include the routes file so that they can all be added to
95 | | the application. This will provide all of the URLs the application
96 | | can respond to, as well as the controllers that may handle them.
97 | |
98 | */
99 |
100 | $app->router->group([
101 | 'namespace' => 'App\Http\Controllers',
102 | ], function ($router) {
103 | require __DIR__.'/../routes/web.php';
104 | });
105 |
106 | return $app;
107 |
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "laravel/lumen",
3 | "description": "The Laravel Lumen Framework.",
4 | "keywords": ["framework", "laravel", "lumen"],
5 | "license": "MIT",
6 | "type": "project",
7 | "require": {
8 | "php": "^7.2.5",
9 | "auth0/auth0-php": "^7.1",
10 | "laravel/lumen-framework": "^7.0"
11 | },
12 | "require-dev": {
13 | "fzaninotto/faker": "~1.4",
14 | "phpunit/phpunit": "~6.0",
15 | "mockery/mockery": "~0.9"
16 | },
17 | "autoload": {
18 | "psr-4": {
19 | "App\\": "app/"
20 | }
21 | },
22 | "autoload-dev": {
23 | "classmap": [
24 | "tests/",
25 | "database/"
26 | ]
27 | },
28 | "scripts": {
29 | "post-root-package-install": [
30 | "php -r \"copy('.env.example', '.env');\""
31 | ]
32 | },
33 | "minimum-stability": "dev",
34 | "prefer-stable": true,
35 | "optimize-autoloader": true
36 | }
37 |
--------------------------------------------------------------------------------
/database/factories/ModelFactory.php:
--------------------------------------------------------------------------------
1 | define(App\User::class, function (Faker\Generator $faker) {
15 | return [
16 | 'name' => $faker->name,
17 | 'email' => $faker->email,
18 | ];
19 | });
20 |
--------------------------------------------------------------------------------
/database/migrations/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/auth0-blog/lumen-api-auth/c3883c792ef3f51fdf9f3d3055012b20a03fb74c/database/migrations/.gitkeep
--------------------------------------------------------------------------------
/database/migrations/2017_12_18_203510_create_authors_table.php:
--------------------------------------------------------------------------------
1 | increments('id');
18 | $table->string('name');
19 | $table->string('email')->unique();
20 | $table->string('github');
21 | $table->string('twitter');
22 | $table->string('location');
23 | $table->string('latest_article_published');
24 | $table->timestamps();
25 | });
26 | }
27 |
28 | /**
29 | * Reverse the migrations.
30 | *
31 | * @return void
32 | */
33 | public function down()
34 | {
35 | Schema::dropIfExists('authors');
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/database/seeds/DatabaseSeeder.php:
--------------------------------------------------------------------------------
1 | call('UsersTableSeeder');
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/phpunit.xml:
--------------------------------------------------------------------------------
1 |
2 |
12 |
13 |
14 | ./tests
15 |
16 |
17 |
18 |
19 | ./app
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/public/.htaccess:
--------------------------------------------------------------------------------
1 |
2 |
3 | Options -MultiViews
4 |
5 |
6 | RewriteEngine On
7 |
8 | # Redirect Trailing Slashes If Not A Folder...
9 | RewriteCond %{REQUEST_FILENAME} !-d
10 | RewriteRule ^(.*)/$ /$1 [L,R=301]
11 |
12 | # Handle Front Controller...
13 | RewriteCond %{REQUEST_FILENAME} !-d
14 | RewriteCond %{REQUEST_FILENAME} !-f
15 | RewriteRule ^ index.php [L]
16 |
17 | # Handle Authorization Header
18 | RewriteCond %{HTTP:Authorization} .
19 | RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
20 |
21 |
--------------------------------------------------------------------------------
/public/index.php:
--------------------------------------------------------------------------------
1 | run();
30 |
--------------------------------------------------------------------------------
/readme.md:
--------------------------------------------------------------------------------
1 | This repo demonstrates how to create a simple API with Lumen, require an access token to access endpoints, and add permission requirements using Auth0.
2 |
3 | For instructions, please [follow the tutorial here](
4 | https://auth0.com/blog/developing-restful-apis-with-lumen).
--------------------------------------------------------------------------------
/resources/views/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/auth0-blog/lumen-api-auth/c3883c792ef3f51fdf9f3d3055012b20a03fb74c/resources/views/.gitkeep
--------------------------------------------------------------------------------
/routes/web.php:
--------------------------------------------------------------------------------
1 | get('/', function () use ($router) {
15 | return $router->app->version();
16 | });
17 |
18 | $router->group(['prefix' => 'api', 'middleware' => 'auth'], function () use ($router) {
19 | $router->get('authors', ['uses' => 'AuthorController@showAllAuthors']);
20 |
21 | $router->get('authors/{id}', ['uses' => 'AuthorController@showOneAuthor']);
22 |
23 | $router->post('authors', ['uses' => 'AuthorController@create']);
24 |
25 | $router->delete('authors/{id}', ['uses' => 'AuthorController@delete']);
26 |
27 | $router->put('authors/{id}', ['uses' => 'AuthorController@update']);
28 | });
--------------------------------------------------------------------------------
/storage/app/.gitignore:
--------------------------------------------------------------------------------
1 | *
2 | !.gitignore
3 |
--------------------------------------------------------------------------------
/storage/framework/cache/.gitignore:
--------------------------------------------------------------------------------
1 | *
2 | !.gitignore
3 |
--------------------------------------------------------------------------------
/storage/framework/views/.gitignore:
--------------------------------------------------------------------------------
1 | *
2 | !.gitignore
3 |
--------------------------------------------------------------------------------
/storage/logs/.gitignore:
--------------------------------------------------------------------------------
1 | *
2 | !.gitignore
3 |
--------------------------------------------------------------------------------
/tests/ExampleTest.php:
--------------------------------------------------------------------------------
1 | get('/');
16 |
17 | $this->assertEquals(
18 | $this->app->version(), $this->response->getContent()
19 | );
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/tests/TestCase.php:
--------------------------------------------------------------------------------
1 |