Skip to content

Commit

Permalink
Split off dakujem/generic-middleware package
Browse files Browse the repository at this point in the history
+ updated dox
  • Loading branch information
dakujem committed Nov 28, 2020
1 parent a484172 commit 6d93a31
Show file tree
Hide file tree
Showing 5 changed files with 57 additions and 127 deletions.
11 changes: 5 additions & 6 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,10 @@
],
"require": {
"php": "^7.4 || ^8.0",
"dakujem/generic-middleware": "^1",
"psr/http-factory": "^1.0",
"psr/http-server-middleware": "^1.0",
"psr/log": "^1.0",
"psr/http-factory": "^1.0"
"psr/log": "^1.0"
},
"require-dev": {
"ext-json": "*",
Expand All @@ -38,9 +39,7 @@
"test:local": "Run application tests with local configuration.",
"test:ci": "Run application tests, provide configuration options as needed."
},
"extra": {
"branch-alias": {
"dev-main": "1.x-dev"
}
"config": {
"sort-packages": true
}
}
101 changes: 52 additions & 49 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,11 @@ Modern and highly flexible PSR-15 authentication and authorization middleware.

## Default Usage

The package makes use of _two_ decoupled middleware implementations:
- `TokenMiddleware` for (JWT) token decoding
- `GenericMiddleware` for token assertion (authentication & authorization)
To use this package, you create **two middleware layers**:
- a **token-decoding** middleware that decodes encoded JWT present in the request and verifies its authenticity
- and a **middleware that authorizes** the request by asserting the presence of the decoded token

Use `AuthWizard` for convenience:
Use `Dakujem\Middleware\AuthWizard` for convenience:
```php
/* @var Slim\App $app */
$app->add(AuthWizard::assertTokens($app->getResponseFactory()));
Expand All @@ -24,9 +24,10 @@ $app->add(AuthWizard::decodeTokens('a-secret-api-key-never-to-commit'));

The pair of middleware (MW) will look for a [JWT](https://jwt.io/introduction/)
in the `Authorization` header or `token` cookie.\
Then it will decode it and inject the decoded payload to the `token` request attribute,
Then it will decode the JWT and inject the decoded payload to the `token` request attribute,
accessible to the application.\
If the token is not present or is not valid, the execution pipeline will be terminated
by the assertion middleware
and a `401 Unauthorized` response will be returned.

The token can be accessed via the request attribute:
Expand All @@ -35,11 +36,15 @@ The token can be accessed via the request attribute:
$decodedToken = $request->getAttribute('token');
```

The assertion can be applied to selected routes instead of every route:
You can choose to apply the assertion to selected routes only instead of every route:
```php
$mwFactory = AuthWizard::factory('a-secret-api-key-never-to-commit', $app->getResponseFactory());
$app->add($mwFactory->decodeTokens()); // decode the token for all routes, but
$app->group('/foo', ...)->add($mwFactory->assertTokens()); // only apply the assertion for selected ones

// Decode the token for all routes,
$app->add($mwFactory->decodeTokens());

// but only apply the assertion to selected ones.
$app->group('/foo', ...)->add($mwFactory->assertTokens());
```

Custom token inspection can be applied too:
Expand All @@ -51,25 +56,15 @@ $app->group('/admin', ...)->add(AuthWizard::inspectTokens(
}
));
```
> To cast the token to a specific class as seen above,
> custom _decoder_ must be used for `TokenMiddleware`, see the next chapters.

For highly flexible options to instantiate the middleware, read the "Compose Your Own Middleware" chapter below.

For the defaults to work (the decoder in particular),
you need to install [Firebase JWT](https://github.com/firebase/php-jwt) package.\
`composer require firebase/php-jwt:"^5.0"`
💡\
For highly flexible options to instantiate the middleware,
read the ["Compose Your Own Middleware"](#compose-your-own-middleware) chapter below.

>
> 💡
>
> You are able to use any other decoder implementation and need not install Firebase JWT package, see below.
>
> The MW can also be used for OAuth tokens or other tokens,
> simply by swapping the default decoder for another one.
>
> The examples use [Slim PHP](https://www.slimframework.com) framework,
> but same applies to any [PSR-15](https://www.php-fig.org/psr/psr-15/) compatible middleware dispatcher.
> The examples above use [Slim PHP](https://www.slimframework.com) framework,
> but the same usage applies to any [PSR-15](https://www.php-fig.org/psr/psr-15/)
> compatible middleware dispatcher.
>

Expand Down Expand Up @@ -128,8 +123,9 @@ AuthWizard::inspectTokens(
'token.error' // what attribute to look for error messages in
);
```
In this case, the pipeline can be terminated on other conditions as well.
Custom error messages or data can be passed to the Response.\
Using `AuthWizard::inspectTokens`, the pipeline can be terminated on any conditions, involving the token or not.\
Custom error messages or data can be passed to the Response.

If the token is not present, the middleware acts the same as the one created by `assertTokens`
and the inspector is not called.

Expand All @@ -143,6 +139,7 @@ AuthWizard::inspectTokens(
}
);
```
The cast can either be done in the decoder or in a separate middleware.


## Compose Your Own Middleware
Expand All @@ -153,12 +150,12 @@ However, it is possible and encouraged to build your own middleware using the co
You have the flexibility to fine-tune the middleware for any use case.

>
> Note that I'm using aliased class names instead of full interface names in this documentation for brevity.
> I'm using aliased names instead of full interface names in this documentation for brevity.
>
> Here are the full interface names:
>
> | Alias | Full class name |
> |:------|:----------------|
> | Alias | Full interface name |
> |:------|:--------------------|
> | `Request` | `Psr\Http\Message\ServerRequestInterface` |
> | `Response` | `Psr\Http\Message\ResponseInterface` |
> | `ResponseFactory` | `Psr\Http\Message\ResponseFactoryInterface` |
Expand Down Expand Up @@ -204,18 +201,31 @@ new TokenMiddleware(
TokenManipulators::attributeInjector('token', 'token.error')
);
```
The decoder should be swapped if you want to use OAuth tokens or a different JWT implementation.
Exceptions may be caught and processed by the injector.

Usage tips 💡:
- The decoder can be swapped in order to use **OAuth tokens** or a different JWT implementation.
- Exceptions may be caught and processed by the _injector_ by wrapping the provider callable in a try-catch block
`try { $token = $provider(); } catch (RuntimeException $e) { ... `
- The decoder may return any object, this is the place to cast the raw payload into your object of choice.
Alternatively, a separate middleware can be used for that purpose.

### `GenericMiddleware`

The [`GenericMiddleware`] is a general purpose middleware that turns a callable into PSR-15 implementation.
It accepts _any_ callable with signature `fn(Request,Handler):Response`.
### `AuthWizard`, `AuthFactory`

[`AuthWizard`] is a friction reducer that helps quickly instantiate token-decoding and assertion middleware with sensible defaults.\
[`AuthFactory`] is a configurable factory with sensible defaults provided for convenience.\
`AuthWizard` internally instantiates `AuthFactory` and acts as a static facade for the factory.

Use `AuthFactory::decodeTokens` to create token-decoding middleware.\
Use `AuthFactory::assertTokens` to create middleware that asserts the presence of a decoded token.\
Use `AuthFactory::inspectTokens` to create middleware with custom authorization rules against the token.


### `GenericMiddleware`

It is used for assertion of token presence and custom authorization by `AuthWizard` / `AuthFactory`.
The [`GenericMiddleware`] is used for assertion of token presence and custom authorization by `AuthWizard` / `AuthFactory`.

It can be used for convenient inline middleware implementation:
It can also be used for convenient inline middleware implementation:
```php
$app->add(new GenericMiddleware(function(Request $request, Handler $next): Response {
$request = $request->withAttribute('foo', 42);
Expand All @@ -225,17 +235,6 @@ $app->add(new GenericMiddleware(function(Request $request, Handler $next): Respo
```


### `AuthWizard`, `AuthFactory`

[`AuthWizard`] is a friction reducer that helps quickly instantiate the middleware with sensible defaults.\
[`AuthFactory`] is a configurable factory with sensible defaults provided for convenience.\
`AuthWizard` internally instantiates `AuthFactory` and acts as a static proxy for the factory.

Use `AuthFactory::decodeTokens` to create token-decoding middleware.\
Use `AuthFactory::assertTokens` to create middleware that asserts the presence of a decoded token.\
Use `AuthFactory::inspectTokens` to create middleware with custom authorization rules against the token.


### `TokenManipulators`

The [`TokenManipulators`] static class provides various request/response manipulators
Expand All @@ -246,7 +245,11 @@ They are used as components of the middleware.
### `FirebaseJwtDecoder`

The [`FirebaseJwtDecoder`] class serves as the default implementation for JWT token decoding.\
It is used as a _decoder_ for the `TokenMiddleware`.
It is used as a _decoder_ for the `TokenMiddleware`.\
You can swap it for a different implementation.

You need to install [Firebase JWT](https://github.com/firebase/php-jwt) package in order to use this decoder.\
`composer require firebase/php-jwt:"^5.0"`


### Logger
Expand Down Expand Up @@ -284,7 +287,7 @@ we'll get in touch and discuss the details privately.


[`TokenMiddleware`]: src/TokenMiddleware.php
[`PredicateMiddleware`]: src/PredicateMiddleware.php
[`GenericMiddleware`]: https://github.com/dakujem/generic-middleware#readme
[`TokenManipulators`]: src/TokenManipulators.php
[`FirebaseJwtDecoder`]: src/FirebaseJwtDecoder.php
[`AuthWizard`]: src/Factory/AuthWizard.php
Expand Down
35 changes: 0 additions & 35 deletions src/GenericHandler.php

This file was deleted.

36 changes: 0 additions & 36 deletions src/GenericMiddleware.php

This file was deleted.

1 change: 0 additions & 1 deletion src/TokenManipulators.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@

namespace Dakujem\Middleware;

use Psr\Http\Message\ResponseFactoryInterface as ResponseFactory;
use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;
use Psr\Http\Server\MiddlewareInterface as Middleware;
Expand Down

0 comments on commit 6d93a31

Please sign in to comment.