PHPackages                             jot/hf-shield - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Search &amp; Filtering](/categories/search)
4. /
5. jot/hf-shield

ActiveLibrary[Search &amp; Filtering](/categories/search)

jot/hf-shield
=============

OAuth2 routes, middlewares and validators

v0.3.103(10mo ago)0758MITPHPPHP &gt;=8.2

Since Feb 7Pushed 10mo ago1 watchersCompare

[ Source](https://github.com/JotJunior/hf-shield)[ Packagist](https://packagist.org/packages/jot/hf-shield)[ RSS](/packages/jot-hf-shield/feed)WikiDiscussions main Synced 3w ago

READMEChangelogDependencies (22)Versions (141)Used By (0)

[![hf-shield HyperF security module](docs/hf-shield.png)](docs/hf-shield.png)

hf-shield
=========

[](#hf-shield)

A module for authentication and authorization management using OAuth 2.0, with robust support for scope hierarchy and authentication flow.

TL/DR
-----

[](#tldr)

Build for:

- OAuth2 authentication
- Cookie-based authentication over OAuth2 JWT Token
- Passkey registration and authentication
- WhatsApp authentication with OTP
- Automatic Swagger documentation
- Easy-to-use code generators

Copy the `docker-compose.yml` file to your project directory and replace the values in the .env file and start the environment.

```
# create your project
composer create-project hyperf/hyperf-skeleton my-project
cd my-project

# install hf-shield
composer require jot/hf-shield
php bin/hyperf.php vendor:publish jot/hf-shield
php bin/hyperf.php vendor:publish jot/hf-repository
php bin/hyperf.php vendor:publish jot/hf-elastic
php bin/hyperf.php vendor:publish jot/hf-validator
php bin/hyperf.php vendor:publish hyperf/swagger
php bin/hyperf.php vendor:publish hyperf/rate-limit
php bin/hyperf.php vendor:publish hyperf/translation

# prepare your environment
cp .env.shield .env

# prepare your database
php bin/hyperf.php elastic:migrate

# configure your tenant
php bin/hyperf.php oauth:scope sync
php bin/hyperf.php oauth:tenant create
php bin/hyperf.php oauth:client create
php bin/hyperf.php oauth:user create

# be happy
php bin/hyperf.php start
```

### Authenticating

[](#authenticating)

**JWT Bearer token**

```
POST /oauth/token
{
    "grant_type": "password",
    "client_id": "client_id",
    "username": "username",
    "password": "password",
    "scope": "oauth: user: settings:"
}

```

**Start a new session**

See .env HF\_SESSION settings

```
POST /oauth/session
{
    "username": "username",
    "password": "password"
}

```

**Registering a passkey**

Client challenging

```
GET /web-auth/challenge

```

Registering authenticator

```
POST /web-auth/register
{
   "credentials": {}
}

```

**Authenticate a passkey**

Start challenge

```
POST /web-auth/login/collect
{
   "userId": "optional"
}

```

Authenticate

```
POST /web-auth/login/validate
{
    "credentials": {}
}

```

This will redirect user for HF\_SESSION redirect\_uri configuration

**Authenticate a WhatsApp number**

```
POST /whatsapp/login/start
{
    "federal_document": "A registered user CPF"
}

```

You will receive the otp id in response and a `code` on your whatsapp that you must enter in the next step.

**Validating the OTP**

For a JWT token

```
POST /whatsapp/login/token
{
    "code": "OTP CODE",
    "otp_id": "OTP ID",
    "client_id": "CLIENT ID",
    "scope": "user: oauth: settings:"
}

```

To start a new session

```
POST /whatsapp/login/cookie
{
    "code": "OTP CODE",
    "otp_id": "OTP ID",
    "client_id": "CLIENT ID",
    "scope": "user: oauth: settings:"
}

```

Table of Contents
-----------------

[](#table-of-contents)

1. [Introduction](#introduction)
2. [Installation](#installation)
3. [Configuration](#configuration)
4. [Translations](#translations)
5. [Defining Permissions](#defining-permissions)
6. [Creating migrations](#creating-migrations)
7. [Code Generators](#code-generators)

---

Introduction
------------

[](#introduction)

**hf-shield** is a module designed to facilitate the implementation of authentication and scope-based access control. It follows the guidelines of the OAuth 2.0 protocol and is especially useful for distributed systems, multi-tenant applications, and APIs that require complex permission hierarchies.

With customizable flows and well-defined validations, **hf-shield** offers a secure and scalable way to ensure access to resources, with validations focused on tokens, users, and clients.

Installation
------------

[](#installation)

Make sure your project uses PHP 8.2 or higher to ensure full compatibility.

To start using **hf-shield**, we suggest first installing `hyperf/hyperf-skeleton`.

```
composer create-project hyperf/hyperf-skeleton my-project
```

During installation, accept the following packages:

- Redis client: `hyperf/redis`
- Config Center: option 3 ETCD
- AMQP Component `hyperf/amqp`
- Elasticsearch component `hyperf/elasticsearch`

After installation, navigate to the project directory and install this module:

```
cd my-project
composer require jot/hf-shield
```

---

Configuration
-------------

[](#configuration)

After installing the module, it needs to be configured. Make sure all dependencies are installed in your environment before starting the service.

You can set up your development environment using the [docker-composer](./docker-compose.yml) in this repository.

### Dependencies

[](#dependencies)

#### ETCD

[](#etcd)

After installing the service in your environment, run the command below:

```
php bin/hyperf.php vendor:publish hyperf/etcd
```

#### REDIS

[](#redis)

All cache management and rate-limiting are stored in Redis. After installing the service, run the command below:

```
php bin/hyperf.php vendor:publish hyperf/redis
```

With the configuration created, publish the credentials to ETCD with the following command:

```
php bin/hyperf.php etcd:put redis
```

#### ELASTICSEARCH

[](#elasticsearch)

This application was built to use Elasticsearch as the main database.

```
php bin/hyperf.php vendor:publish jot/hf-elastic
```

After editing the `.env` file with the necessary credentials, register them in etcd:

```
php bin/hyperf.php etcd:put hf_elastic
```

#### SWAGGER

[](#swagger)

The code generation commands provided by the `jot/hf-repository` module already create controllers, entities, and data repositories with the necessary Swagger basics, which means the application is born with documented APIs.

```
php bin/hyperf.php vendor:publish jot/hf-repository
```

#### RATE-LIMIT

[](#rate-limit)

Like Swagger, the `jot/hf-repository` module also implements the application's throttling configuration, which can be configured globally and reimplemented on a case-by-case basis in controller methods through their *annotations*.

```
php bin/hyperf.php vendor:publish hyperf/rate-limit
```

#### OAUTH2

[](#oauth2)

Finally, add the configurations for this module to work:

```
php bin/hyperf.php vendor:publish jot/hf-shield
```

**Example of `config/autoload/hf_shield.php`:**

```
return [
    'token_format' => 'JWT',            // token format. By default, JWT
    'private_key' => '',                // path or content of the private key
    'public_key' => '',                 // path or content of the public key
    'encryption_key' => '',             // string for data encryption
    'token_days' => 'P1D',              // token validity in PHP DateTimeInterval format
    'refresh_token_days' => 'P1M',      // refresh token validity in PHP DateTimeInterval format
    'revoke_user_old_tokens' => true,   // enables trigger that revokes previous user/client tokens
];
```

#### MIGRATIONS

[](#migrations)

After everything is configured, it's time to run the migrations so that the necessary indices for the authentication process are created:

```
php bin/hyperf.php elastic:migrate
```

---

Translations
------------

[](#translations)

**hf-shield** supports internationalization (i18n) using the hyperf/translation package. Translation files are located in `storage/languages/{locale}/hf-shield.php`.

Currently, the module supports the following languages:

- English (en)
- Brazilian Portuguese (pt\_BR)

To add support for a new language, create a new translation file following the existing pattern.

### Publishing Translations

[](#publishing-translations)

Translations are automatically published when you run the package publish command:

```
php bin/hyperf.php vendor:publish hyperf/translation
php bin/hyperf.php vendor:publish jot/hf-shield
```

Additional packages translations will be automatically published when you publish the `hf-*` package.

eg:

```
php bin/hyperf.php vendor:publish jot/hf-elastic
php bin/hyperf.php vendor:publish jot/hf-validator
php bin/hyperf.php vendor:publish jot/hf-repository
```

### Customizing Translations

[](#customizing-translations)

You can customize translations by editing the files in `storage/languages/{locale}/messages.php`. Translation keys are organized into the following categories:

- Command messages (for CLI)
- Form labels and prompts
- Exception messages

---

Defining Permissions
--------------------

[](#defining-permissions)

### Scopes

[](#scopes)

Scopes are automatically implemented in controllers when created by the repo:controller or repo:crud command, but if you are implementing a controller manually, add the following docblock before the desired action:

```
#[Scope(allow: 'service:resource:permission')]
public function myAction(string $id): PsrResponseInterface {
   // ...
}
```

#### Scope Naming Rules

[](#scope-naming-rules)

Scopes should be named following this pattern: `[service]:[resource]:[permission]`

Examples:

```
api-events:event:list
api-events:event:create
api-shopping:order:create
api-shopping:order:update
api-shopping:order:list

```

To register the scopes in the application, run the command below:

```
php bin/hyperf.php oauth:scope sync
```

### Token Validation

[](#token-validation)

If you want your action to be protected by token, you must add the middleware with the desired validation strategy:

```
#[Middleware(middleware: BearerStragegy::class)]
```

Currently, there are 3 types of strategies for request validation:

1. **BearerStrategy**, validates the token through the Authorization header: Bearer *{token}*, generated by the `/oauth/token` endpoint.
2. **SessionStrategy**, validates the token from the access\_token cookie, generated by the '/oauth/session' endpoint, which encrypts the token and sends it to the browser cookies.
3. **SignedJwtStrategy**, validates the token by its signature. In this case, the payload is sent in the JWT and validated by the user's signature.

---

### API Validation Scope Hierarchy

[](#api-validation-scope-hierarchy)

The following diagram describes how the scope hierarchy works in **hf-shield**:

 ```
flowchart TD
    tenant[Tenant]
    client[Client]
    user[User]
    token[Token]
    scope[Scope]
%% Revised hierarchical relationships:
    tenant -->|Has one or more| client
    client -->|Is used to create| token
    token -->|Is created by| user
    token -->|Contains authorized Client scopes| scope
    client -->|Links scopes considering the Tenant| scope
    user -->|Related to Tenant scopes| scope
```

      Loading ### Authentication Flow

[](#authentication-flow)

The authentication flow expected by **hf-shield** is described in the diagram below:

 ```
flowchart TD
    start((REQUEST))
    validateToken[Verify token signature, validity, and metadata]
    invalidToken[HTTP 401: UnauthorizedAccessException]
    checkResourceScopes[Check if the resource has linked scopes]
    missingResourceScope[HTTP 400: MissingResourceScopeException]
    checkTokenScopes[Check if the token has the necessary scopes]
    unauthorizedToken[HTTP 401: UnauthorizedAccessException]
    validateClient[Check if the client is valid and active]
    invalidClient[HTTP 401: UnauthorizedClientException]
    validateUser[Check if the User is valid, active, and has the necessary scopes]
    unauthorizedUser[HTTP 401: UnauthorizedUserException]
    success[HTTP 200: User can access the desired resource]
    response((RESPONSE))
%% Main flow
    start --> validateToken
    validateToken -->|Valid| checkResourceScopes
    validateToken -->|Invalid| invalidToken
    checkResourceScopes -->|Linked| checkTokenScopes
    checkResourceScopes -->|Not Linked| missingResourceScope
    checkTokenScopes -->|Sufficient Scopes| validateClient
    checkTokenScopes -->|Insufficient Scopes| unauthorizedToken
    validateClient -->|Valid| validateUser
    validateClient -->|Invalid| invalidClient
    validateUser -->|Invalid| unauthorizedUser
    validateUser -->|Valid| success
    success --> response
```

      Loading ---

Creating migrations
-------------------

[](#creating-migrations)

Inspired by [Laravel](https://laravel.com) migrations, the [hf-elastic](https://github.com/JotJunior/hf-elastic) module, part of the hf-shield ecosystem, allows you to create your indices quickly and dynamically, either manually or from JSON examples or JSON Schemas, and is prepared for all known types of [Elasticsearch](https://elastic.co) in version 8.x.

### Creating a migration manually

[](#creating-a-migration-manually)

```
php bin/hyperf elastic:migration my_awesome_index
```

As a result, it will create a file in the format `YYYYmmdd-create-my_awesome_index.php` in the `migrations/elasticsearch` directory.

The generated file will be in this format:

```
