# @marblejs-contrib/middleware-jwt

This module lets you authenticate HTTP requests using JWT tokens in your **Marble.js** applications. JWTs are typically used to protect API endpoints, and are often issued using OpenID Connect.

{% hint style="warning" %}
Since version 4.0, the middleware is a part of contrib packages. You can reach it via `@marblejs-contrib/middleware-joi`.
{% endhint %}

{% hint style="info" %}
You can find more details about JWT (RFC 7519) standard [here](http://jwt.io).
{% endhint %}

The middleware uses `jsonwebtoken` package under the hood. It wraps the package API into more\
RxJS-friendly abstractions that can be partially applied and composed inside Effect streams.

### Installation

```bash
yarn add @marblejs-contrib/middleware-jwt
```

Requires `@marblejs/core` to be installed.

### Importing

```typescript
import { authorize$ } from '@marblejs-contrib/middleware-jwt';
```

### Type declaration

```
authorize$ :: (VerifyOptions, object -> Observable<object>) -> HttpMiddlewareEffect
```

### **Parameters**

| *parameter*      | definition                                |
| ---------------- | ----------------------------------------- |
| *config*         | `VerifyOptions`                           |
| *verifyPayload$* | `(payload: object) => Observable<object>` |

{% tabs %}
{% tab title="verifyPayload$" %}
A function used for payload verification. With this handler we can check if the payload extracted from the JWT token fulfills our security criterias (eg. we can verify if the given user identifier exists in the database). Besides the general verification, the function can return the streamed object, that will be available inside *HttpRequest* `req.user` parameter. If the stream throws an error (eg. during the validation) the *authorize$* middleware responds with `401 / Unauthorized` error.

**Type declaration**

```
verifyPayload$ :: object -> Observable<object>
```

**Example**

The function checks the presence of the user id in the database and then returns an *Observable* of found user instance.&#x20;

{% code title="" %}

```typescript
const verifyPayload$ = (payload: Payload) => UserDao
  .findById(payload._id)
  .pipe(flatMap(neverNullable));
```

{% endcode %}
{% endtab %}

{% tab title="VerifyOptions" %}
Config object, passed as a first argument, defines a set of parameters that are used during token verification process.

| *parameter*      | definition                       |
| ---------------- | -------------------------------- |
| *secret*         | `string \| Buffer`               |
| algorithms       | \<optional>  `string[]`          |
| audience         | \<optional> `string \| string[]` |
| clockTimestamp   | \<optional> `number`             |
| clockTolerance   | \<optional> `number`             |
| issuer           | \<optional> `string \| string[]` |
| ignoreExpiration | \<optional> `boolean`            |
| ignoreNotBefore  | \<optional> `boolean`            |
| jwtid            | \<optional> `string`             |
| subject          | \<optional> `string`             |
| {% endtab %}     |                                  |
| {% endtabs %}    |                                  |

{% hint style="info" %}
For more infos about `jwt.VerifyOptions` please read [jsonwebtoken docs](https://github.com/auth0/node-jsonwebtoken#jwtverifytoken-secretorpublickey-options-callback).
{% endhint %}

{% hint style="info" %}
You can read more about token creation [here](https://marblejs.gitbook.io/docs/other/api-reference/middleware-jwt/token-creation).
{% endhint %}

### **Usage**

It is recommended to extract the middleware configuration into separate file. This way you can reuse it in many places.

{% code title="auth.middleware.ts" %}

```typescript
import { authorize$ as jwt$ } from '@marblejs-contrib/middleware-jwt';
import { SECRET_KEY } from './config';

const config = { secret: SECRET_KEY };

const verifyPayload$ = (payload: Payload) => UserDao
  .findById(payload._id)
  .pipe(flatMap(neverNullable));

export const authorize$ = jwt$(config, verifyPayload$);
```

{% endcode %}

The configured middleware can be simply composed in any route, that should be validated.

```typescript
import { r } from '@marblejs/http';
import { authorize$ } from './auth-middleware';

const getUsers$ = r.pipe(
  r.matchPath('/'),
  r.matchType('GET'),
  r.useEffect(getUsersEffect$)));

const user$ = combineRoutes('/user', {
  effects: [getUsers$],
  middlewares: [authorize$], 👈
});
```

If the incoming request doesn't pass the authentication process (eg. token is invalid, expired or the `verifyPayload$` throws an error, the middleware responds with `401 / Unauthorized` error.
