Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Authentification passport #3

Open
wants to merge 8 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
84 changes: 4 additions & 80 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,84 +1,8 @@
# Laravel 10 API Skeleton 📦
This project is a skeleton for setting up an API with Laravel. It contains several ways and architectures to build an API with Laravel.
# Laravel API Skeleton - Example
This project is a skeleton for building an API with Laravel. It is the simplest skeleton and contains only the basic packages to build an API.

## Introduction 📖
As each API project is different, it's not easy to have a boilerplate that will cover all cases. Some APIs may need roles, others may not.
Some may need to set up authentication with [Sanctum](https://laravel.com/docs/10.x/sanctum), others with [JWT](https://github.com/tymondesigns/jwt-auth), others with [Passport](https://laravel.com/docs/10.x/passport) and so on.

All these cases are huge and complex. This project aims to build several skeletons that can be used when the need arises.
And you'll end up building the architecture you want for your next API project.

You can see here an example of a model like Vercel with [Nextjs](https://github.com/vercel/next.js), which has several sample implementations.

## Getting Started 🚀
If you want to contribute to the Laravel API Skeleton repo:

- Fork this repository to your GitHub account. Then clone your forked repository and cd into it.
- Clone the repository
```bash
git clone https://github.com/{username}/api-skeleton.git api-skeleton && cd api-skeleton
```
- In your fork, create a branch for your skeleton, e.g. `feature/authentication-with-passport`.

Then, install the dependencies `composer install`

## Architecture 🏗
The project has only 2 folders
- `projets` the folder where all API skeletons will be stored to start an API project with Laravel
- `skeleton` is the folder containing the commands to generate a skeleton once you've finished building it.

## Available Skeletons 📚
To get the list of available skeletons, run the command:

```bash
./skeleton/bin/project available
```

All skeletons are available in the `projects` folder. Each skeleton is a Laravel project and containing a `composer.json` file and a `README.md` file.


## Usage 📝
To create a new skeleton, run the following command:

> To build a skeleton, you have to base it on an existing skeleton. The `default` skeleton is the simplest.
Once you've selected a skeleton, all the code in the skeleton's folder `projects/default` will be available at the root of the project,
and you'll need to do another compose install to install the Laravel project's dependencies.
## Installation

```bash
./skeleton/bin/project use {skeleton-name}
composer require laravelcm/api-skeleton
```

## Autoload
When you use a skeleton, it will overwrite the default root composer.json file and the commands for generating the project will no longer be available. To fix this, you need to autoload the skeleton folder using psr-4. Like this:

```json
{
"autoload": {
"psr-4": {
"App\\": "app/",
"Core\\": "core/",
"Skeleton\\": "skeleton/",
"Database\\Factories\\": "database/factories/",
"Database\\Seeders\\": "database/seeders/"
}
}
}
```

**Tip: don't forget to run composer dump-autoload afterward.**

Once you have built your skeleton and are satisfied with your work, you can generate a project and all the modifications you have made will be added only to the skeleton you have created.

```bash
./skeleton/bin/project generate {skeleton-name}
```

This command will create a new Laravel project in the `projects` folder with the name of your skeleton. And you can publish it on packagist composer or if you like.
Before pushing your branch and making a PR, you need to run the following command to reset the project to its original state.

```bash
./skeleton/bin/project reset
```

## Contributing 🤝
Feel free to create any pull requests for the project. If you have any questions, please you can create an issue.
Empty file added app/Console/Commands/.gitkeep
Empty file.
13 changes: 13 additions & 0 deletions app/Enum/Error.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?php

declare(strict_types=1);

namespace App\Enum;

enum Error: string
{
case AUTH_001 = 'https://docs.api.com/errors/auth_001';
case AUTH_002 = 'https://docs.api.com/errors/auth_002';
case AUTH_003 = 'https://docs.api.com/errors/auth_003';
case AUTH_004 = 'https://docs.api.com/errors/auth_004';
}
Empty file added app/Exceptions/.gitkeep
Empty file.
15 changes: 15 additions & 0 deletions app/Http/Controllers/Controller.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?php

declare(strict_types=1);

namespace App\Http\Controllers;

use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
use Illuminate\Foundation\Validation\ValidatesRequests;
use Illuminate\Routing\Controller as BaseController;
use Illuminate\Http\Request;

class Controller extends BaseController
{
use AuthorizesRequests, ValidatesRequests;
}
20 changes: 20 additions & 0 deletions app/Http/Controllers/HomeController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<?php

declare(strict_types=1);

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use JustSteveKing\Launchpad\Http\Responses\MessageResponse;

final class HomeController
{
public function __invoke(Request $request): MessageResponse
{
return new MessageResponse(
data: [
'message' => __('messages.welcome'),
],
);
}
}
Empty file.
68 changes: 68 additions & 0 deletions app/Http/Controllers/V1/AuthController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
<?php

namespace App\Http\Controllers\V1;

use App\Models\User;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Illuminate\Http\JsonResponse;
use App\Http\Controllers\Controller;
use App\Http\Requests\Auth\LoginRequest;
use App\Http\Requests\Auth\RegisterRequest;
use Illuminate\Support\Facades\Auth;

class AuthController extends Controller
{
public function register(RegisterRequest $request): JsonResponse
{
$data = $request->validated();

$data['password'] = bcrypt($request->password);

$user = User::create($data);

$token = $user->createToken('AUTHTOKEN')->accessToken;

return response()->json([
'message' => 'Success',
'user' => $user,
'token' => $token,
], Response::HTTP_CREATED);
}

public function login(LoginRequest $request): JsonResponse
{
$data = $request->validated();

if (!Auth::attempt($data)) {
return response()->json([
'error' => 'Invalid credentials',
], Response::HTTP_UNAUTHORIZED);
}

$user = Auth::user();

$token = $user->createToken('AUTHTOKEN')->accessToken;

return response()->json([
'user' => $user,
'token' => $token,
], Response::HTTP_ACCEPTED);
}

public function logout(): JsonResponse
{
Auth::user()->tokens->each(function ($token, $key) {
$token->delete();
});

return response()->json(['message' => 'logged out successfully'], Response::HTTP_NO_CONTENT);
}

public function getUser(): JsonResponse
{
$user = Auth::user();

return response()->json(['user' => $user], Response::HTTP_ACCEPTED);
}
}
48 changes: 48 additions & 0 deletions app/Http/Middleware/CacheHeaders.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
<?php

declare(strict_types=1);

namespace App\Http\Middleware;

use Closure;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Symfony\Component\HttpFoundation\Response;

final class CacheHeaders
{
public function handle(Request $request, Closure $next): Response
{
/**
* @var \Illuminate\Http\Response $response
*/
$response = $next($request);

if (Auth::check()) {
$response->setCache(
options: [
'private' => true,
'max_age' => 0,
's_maxage' => 0,
'no_store' => true
],
);
} else {
$response->setCache(
options: [
'public' => true,
'max_age' => 60,
's_maxage' => 60,
],
);

foreach ($response->headers->getCookies() as $cookie) {
$response->headers->removeCookie(
name: $cookie->getName(),
);
}
}

return $response;
}
}
27 changes: 27 additions & 0 deletions app/Http/Middleware/ContentTypeMiddleware.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<?php

declare(strict_types=1);

namespace App\Http\Middleware;

use Closure;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;

final class ContentTypeMiddleware
{
public function handle(Request $request, Closure $next): Response
{
/**
* @var Response $response
*/
$response = $next($request);

$response->headers->add([
'Accept' => 'application/json',
'Content-Type' => 'application/vnd.api+json',
]);

return $response;
}
}
12 changes: 12 additions & 0 deletions app/Http/Middleware/EncryptCookies.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<?php

declare(strict_types=1);

namespace App\Http\Middleware;

use Illuminate\Cookie\Middleware\EncryptCookies as Middleware;

final class EncryptCookies extends Middleware
{
protected $except = [];
}
24 changes: 24 additions & 0 deletions app/Http/Middleware/EnsureEmailIsVerified.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<?php

declare(strict_types=1);

namespace App\Http\Middleware;

use Closure;
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;

final class EnsureEmailIsVerified
{
public function handle(Request $request, Closure $next, string $redirectToRoute = null): Response
{
if ( ! $request->user() ||
($request->user() instanceof MustVerifyEmail &&
! $request->user()->hasVerifiedEmail())) {
return response()->json(['message' => __('Your email address is not verified.')], 409);
}

return $next($request);
}
}
12 changes: 12 additions & 0 deletions app/Http/Middleware/PreventRequestsDuringMaintenance.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<?php

declare(strict_types=1);

namespace App\Http\Middleware;

use Illuminate\Foundation\Http\Middleware\PreventRequestsDuringMaintenance as Middleware;

final class PreventRequestsDuringMaintenance extends Middleware
{
protected $except = [];
}
26 changes: 26 additions & 0 deletions app/Http/Middleware/Security/XFrameOptionMiddleware.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<?php

declare(strict_types=1);

namespace App\Http\Middleware\Security;

use Closure;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;

final class XFrameOptionMiddleware
{
public function handle(Request $request, Closure $next): Response
{
/**
* @var Response $response
*/
$response = $next($request);

$response->headers->add([
'X-Frame-Options' => 'deny',
]);

return $response;
}
}
21 changes: 21 additions & 0 deletions app/Http/Middleware/TrimStrings.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<?php

declare(strict_types=1);

namespace App\Http\Middleware;

use Illuminate\Foundation\Http\Middleware\TrimStrings as Middleware;

final class TrimStrings extends Middleware
{
/**
* The names of the attributes that should not be trimmed.
*
* @var array<int, string>
*/
protected $except = [
'current_password',
'password',
'password_confirmation',
];
}
Loading