Skip to content

Commit

Permalink
Merge pull request #280 from spatie/feat/authorized-endpoint
Browse files Browse the repository at this point in the history
Extend /api/members endpoint
  • Loading branch information
freekmurze authored Oct 9, 2023
2 parents 9ea5a4d + 2e20845 commit 3d418bf
Show file tree
Hide file tree
Showing 14 changed files with 322 additions and 34 deletions.
2 changes: 2 additions & 0 deletions app/Http/Api/Controllers/MembersController.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ public function index()
$members = Member::all()
->map(fn (Member $member) => [
'name' => $member->name(),
'email' => $member->email,
'birthday' => $member->birthday->toDate()->format('Y-m-d'),
'twitter' => $member->twitter,
'website' => $member->website,
]);
Expand Down
22 changes: 22 additions & 0 deletions app/Http/Auth/Controllers/ApiTokensController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<?php

namespace App\Http\Auth\Controllers;

use Illuminate\Http\Request;
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;

class ApiTokensController
{
public function create(Request $request): array
{
$user = $request->user();

if ($user === null || ! $user->isSpatieMember()) {
throw new BadRequestHttpException('You are not a Spatie member');
}

$token = $user->createToken('api-token');

return ['token' => $token->plainTextToken];
}
}
2 changes: 2 additions & 0 deletions app/Http/Kernel.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
namespace App\Http;

use App\Http\Middleware\AddImpersonateOverlay;
use App\Http\Middleware\AdminsOnly;
use App\Http\Middleware\ForceJsonResponse;
use App\Http\Middleware\HandleReferrer;
use App\Http\Middleware\PreventRequestsDuringMaintenance;
Expand Down Expand Up @@ -50,5 +51,6 @@ class Kernel extends HttpKernel
'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
'signed' => \Illuminate\Routing\Middleware\ValidateSignature::class,
'forceJson' => ForceJsonResponse::class,
'adminsOnly' => AdminsOnly::class,
];
}
3 changes: 3 additions & 0 deletions app/Models/Member.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,15 @@

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Spatie\SchemaOrg\Person;
use Spatie\SchemaOrg\Schema;

class Member extends Model
{
use HasFactory;

protected $casts = [
'birthday' => 'immutable_datetime'.':nullable',
'created_at' => 'immutable_datetime',
Expand Down
2 changes: 2 additions & 0 deletions app/Models/User.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,14 @@
use Illuminate\Support\Collection;
use Laravel\Nova\Auth\Impersonatable;
use Laravel\Paddle\Billable;
use Laravel\Sanctum\HasApiTokens;
use Spatie\Comments\Models\Concerns\InteractsWithComments;
use Spatie\Comments\Models\Concerns\Interfaces\CanComment;

class User extends Authenticatable implements CanComment
{
use HasFactory;
use HasApiTokens;
use Billable;
use Notifiable;
use InteractsWithComments;
Expand Down
1 change: 1 addition & 0 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
"laravel/framework": "^10.0",
"laravel/horizon": "^5.12",
"laravel/nova": "^4.17.1",
"laravel/sanctum": "^3.3",
"laravel/slack-notification-channel": "^2.5",
"laravel/socialite": "^5.6",
"laravel/tinker": "^2.8",
Expand Down
68 changes: 67 additions & 1 deletion composer.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

83 changes: 83 additions & 0 deletions config/sanctum.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
<?php

use Laravel\Sanctum\Sanctum;

return [

/*
|--------------------------------------------------------------------------
| Stateful Domains
|--------------------------------------------------------------------------
|
| Requests from the following domains / hosts will receive stateful API
| authentication cookies. Typically, these should include your local
| and production domains which access your API via a frontend SPA.
|
*/

'stateful' => explode(',', env('SANCTUM_STATEFUL_DOMAINS', sprintf(
'%s%s',
'localhost,localhost:3000,127.0.0.1,127.0.0.1:8000,::1',
Sanctum::currentApplicationUrlWithPort()
))),

/*
|--------------------------------------------------------------------------
| Sanctum Guards
|--------------------------------------------------------------------------
|
| This array contains the authentication guards that will be checked when
| Sanctum is trying to authenticate a request. If none of these guards
| are able to authenticate the request, Sanctum will use the bearer
| token that's present on an incoming request for authentication.
|
*/

'guard' => ['web'],

/*
|--------------------------------------------------------------------------
| Expiration Minutes
|--------------------------------------------------------------------------
|
| This value controls the number of minutes until an issued token will be
| considered expired. This will override any values set in the token's
| "expires_at" attribute, but first-party sessions are not affected.
|
*/

'expiration' => null,

/*
|--------------------------------------------------------------------------
| Token Prefix
|--------------------------------------------------------------------------
|
| Sanctum can prefix new tokens in order to take advantage of various
| security scanning initiaives maintained by open source platforms
| that alert developers if they commit tokens into repositories.
|
| See: https://docs.github.com/en/code-security/secret-scanning/about-secret-scanning
|
*/

'token_prefix' => env('SANCTUM_TOKEN_PREFIX', ''),

/*
|--------------------------------------------------------------------------
| Sanctum Middleware
|--------------------------------------------------------------------------
|
| When authenticating your first-party SPA with Sanctum you may need to
| customize some of the middleware Sanctum uses while processing the
| request. You may change the middleware listed below as required.
|
*/

'middleware' => [
'authenticate_session' => Laravel\Sanctum\Http\Middleware\AuthenticateSession::class,
'encrypt_cookies' => App\Http\Middleware\EncryptCookies::class,
'verify_csrf_token' => App\Http\Middleware\VerifyCsrfToken::class,
],

];
21 changes: 21 additions & 0 deletions database/factories/MemberFactory.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<?php

namespace Database\Factories;

use Illuminate\Database\Eloquent\Factories\Factory;

class MemberFactory extends Factory
{
public function definition(): array
{
$name = $this->faker->firstName();

return [
'first_name' => ucfirst($name),
'last_name' => $this->faker->lastName(),
'email' => "${name}@spatie.be",
'description' => '',
'role' => 'Backend Developer',
];
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class () extends Migration {
public function up(): void
{
Schema::create('personal_access_tokens', function (Blueprint $table) {
$table->id();
$table->morphs('tokenable');
$table->string('name');
$table->string('token', 64)->unique();
$table->text('abilities')->nullable();
$table->timestamp('last_used_at')->nullable();
$table->timestamp('expires_at')->nullable();
$table->timestamps();
});
}
};
5 changes: 4 additions & 1 deletion routes/api.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
use App\Http\Api\Controllers\PriceController;
use App\Http\Api\Controllers\SatisAuthenticationController;
use App\Http\Api\Controllers\ShowLicenseController;
use App\Http\Auth\Controllers\ApiTokensController;
use App\Http\Middleware\IsValidHelpSpaceRequest;
use Illuminate\Support\Facades\Route;

Expand All @@ -34,4 +35,6 @@

Route::get('license/{license:key}', ShowLicenseController::class);

Route::get('members', [MembersController::class, 'index']);
Route::get('members', [MembersController::class, 'index'])->middleware(['auth:sanctum', 'adminsOnly']);

Route::post('tokens', [ApiTokensController::class, 'create'])->middleware('adminsOnly');
Loading

0 comments on commit 3d418bf

Please sign in to comment.