# Custom Auth Provider Example

> Build your own token provider in API Maker with jose — sign it, validate it, and read the payload from g.req.auth.authCustom.

Source: https://docs.apimaker.dev/v1/examples/req/auth/authCustom.html

### Custom authorization

To get the value of request header `x-custom-authorization`, use `g.req.auth.authCustom`.

```ts
const custom_auth = g.req.auth.authCustom;
```

Whatever your **Token Validator** function returns is what lands in `g.req.auth.authCustom`. Return the decoded JWT payload and you get the decoded token there — return your own object and you get that instead.

## Why a custom provider?

AM, database, AWS, Azure and Google cover most cases. But sometimes the token is yours — your own claims, your own signing key, your own expiry rules. That is what a **Custom Token Generator** is for: you write the code that mints the token and the code that checks it, and API Maker handles the rest of the request pipeline.

Below is a complete working example using [jose](https://www.npmjs.com/package/jose).

---

### 1. Install the `jose` package

Go to **Utility → Sandbox Settings → Sandbox Dependencies** and add `jose`.

Once added, it is available in every custom code of API Maker, including the two functions below.

---

### 2. Create the auth provider

Go to **API Security → Auth Providers**, click **+** and pick **Custom Token Generator**.

You will get three tabs: **Basic Info**, **Token Generator** and **Token Validator**.

#### Basic Info

```ts
import * as T from 'types';

let customTokenBasicInfo: Partial<T.IAuthTokenAMDB> = {
    name: 'jose_example',
    runOnNativeProcess: false,
};
module.exports = customTokenBasicInfo;
```

- `name` is how you will refer to this provider everywhere else — in the get-token request and in the `authProviders` array of your settings files.
- Keep `runOnNativeProcess` as `false` so the code runs inside the sandbox, where your npm packages live.

#### Token Generator

Runs when someone asks for a token. Whatever you return is sent back to the caller as-is.

```ts
import * as T from 'types';
import * as db from 'db-interfaces';
import { SignJWT } from "jose";

// Produce and return a token string from the request context.
// Runs at token-generation time.
async function main(g: T.IAMGlobal) {
    const body: { role: string, userId: string } = g.req.body;
    const secretFETransfer = await g.sys.system.getSecret('common.secretFETransfer');
    const secret = new TextEncoder().encode(secretFETransfer);

    const accessToken = await new SignJWT({
        // set your required data
        role: body.role,
        email: "mayur@example.com",
        companyId: "cmp_123",
    }).setProtectedHeader({
        alg: "HS256",
        typ: "JWT",
    }).setSubject(body.userId)
        .setIssuedAt()
        .setExpirationTime("15m")
        .setJti(crypto.randomUUID())
        .sign(secret);

    return {
        access_token: accessToken,
        refresh_token: 'refresh_token_test',
        validity: 19200
    };
};
module.exports = main;
```

The whole request body reaches this function as `g.req.body`, so you decide what your login payload looks like.

#### Token Validator

Runs on every request that carries the `x-custom-authorization` header. The token is in `g.req.body.token`.

```ts
import * as T from 'types';
import * as db from 'db-interfaces';
import { jwtVerify } from "jose";

// Validate an incoming token. Return a truthy object (usually the decoded payload) to mark valid.
// Throw or return null/undefined to mark invalid.
async function main(g: T.IAMGlobal) {
    const accessToken = g.req.body.token;
    const secretFETransfer = await g.sys.system.getSecret('common.secretFETransfer');
    const secret = new TextEncoder().encode(secretFETransfer);

    const { payload } = await jwtVerify(accessToken, secret, {
        algorithms: ["HS256"],
    });

    return payload;

    // return true; // if truthy value returned, means token is valid.
    // return false; // if token is not valid
    // return {}; // You can return some object also and it means token is valid.
};
module.exports = main;
```

The rule is simple — **truthy means valid**. Anything falsy, or a thrown error, means the request is rejected.

---

### 3. Generate a token

Request Method: POST

URL
```text
/api/system-api/user-path/token
```

```json
{
    "name": "jose_example",
    "userId": "user_123",
    "role": "admin"
}
```

- `name` tells API Maker which auth provider to run. Everything else in the body is yours and is passed straight to your Token Generator as `g.req.body`.
- For more information about this API [click here](https://docs.apimaker.dev/v1/docs/apis-all/system-apis/system-generated-token-api.html).

Response — exactly what your generator returned:

```json
{
    "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
    "refresh_token": "refresh_token_test",
    "validity": 19200
}
```

---

### 4. Send the token

Put the `access_token` in the `x-custom-authorization` header on every call:

```text
x-custom-authorization: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
```

To let an API accept this provider, add its name to `authProviders` in your settings file:

```ts
authProviders: <string[]>["jose_example"],
```

---

### 5. Read it in your custom code

```ts
import * as T from 'types';

async function main(g: T.IAMGlobal) {
    const auth = g.req.auth.authCustom;

    g.logger.log(auth.sub);        // user_123
    g.logger.log(auth.role);       // admin
    g.logger.log(auth.companyId);  // cmp_123

    return { ok: true };
};
module.exports = main;
```

By the time your code runs, the token is already verified — API Maker rejects bad ones before they reach you. So `g.req.auth.authCustom` is safe to trust.

## Related

- [The global object g](https://docs.apimaker.dev/v1/docs/pre-defined-terms/global-object-g.html) · [Custom APIs](https://docs.apimaker.dev/v1/docs/apis-all/custom-apis/user-created-custom-api.html)
