# Auth of a Database User

> Sign the people of your own users table in with API Maker - a DB auth provider names the table and its columns, the token API gives the person a token, x-am-user-authorization carries it, and the groups column decides what the person may call.

Source: https://docs.apimaker.dev/v1/docs/authorization/AMDB.html

Your users are rows of a table of yours. An **auth provider** of type DB tells API Maker where : the table, the username column, the password column, the groups column. From then on the [token API](https://docs.apimaker.dev/v1/docs/apis-all/system-apis/system-generated-token-api.html) signs those people in, and every call carries their token in `x-am-user-authorization`.

> Diagram : Two tokens, two gates : the API user (which application) and the person (which rows)
>
> Two identities on every request : the API user token from the token API in x-am-authorization tells which application calls, and the token of a person from a token generator in x-am-user-authorization tells who the person is. Groups of the API user decide which APIs, tables and fields may be called ; pre hooks decide which rows belong to the person.

| | |
|---|---|
| Page | `API Security → Auth Providers` : one provider per users table. Types : DB, AWS Cognito, Azure AD, Google, Custom. |
| Header | `x-am-user-authorization: <token>` |
| Get it | `POST /api/system-api/<user path>/token` with `{ "name": "<provider>", "u", "p" }` |
| Require it | `authProviders: ['<provider>']` in the settings of an API, a table, a database, or in `common.authProviders` of the secret. |
| In code | `g.req.auth.authAMDB` : the row of the person, without its password. |

## 1. Declare the provider

**Basic Info of the provider**

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

let dbTokenGenerator: T.IAuthTokenAMDB = {
    name: 'users_tg',
    instance: 'mongodb',
    database: 'shop',
    collection: 'users',                      // table: '…' for SQL
    usernameColumn: 'email',
    passwordColumn: 'password',               // a hashed column works : the password sent is hashed and compared
    passwordChangedAtColumn: 'passwordChangedAt',   // optional : the token carries this value instead of the password fingerprint
    groupsColumn: 'groups',                   // comma separated group names ; '*' = every group of the API user
    expiresInSeconds: 259200,
    runOnNativeProcess: false,                // where the Fields Generator runs
};
module.exports = dbTokenGenerator;
```

- `select` limits the columns of the person put in `g.req.auth.authAMDB` ; `condition` adds a filter to the lookup (`{ active: true }`).
- `passwordChangedAtColumn` : update it whenever a password changes, and every token made before stops working, refresh tokens included. A token made while the column of the person is still empty ends with its first value.
- Without that column the token carries a fingerprint of the stored password (`amfp1:…`, a keyed hash made with the signing secret of the server), never the password or its hash : a changed password ends the tokens made before, and nothing about the password can be read out of a token.

## 2. Require it on the APIs

**Settings of an API, a table or a database**

```typescript
let settings: T.IInstanceApiSettingsTypes = {
    apiAccessType: T.EAPIAccessType.TOKEN_ACCESS,
    authProviders: ['users_tg'],
};
module.exports = settings;
```

- Without `authProviders` in any settings, the APIs need what `common.authProviders` of the [secret](https://docs.apimaker.dev/v1/docs/secrets/secrets.html) names ; nothing there means the API user token alone.
- Several DB providers in the list : a token of any of them works. A provider of another type in the list (Google…) adds its own header to what the call must carry.
- A token works only for the provider which made it, in the account which made it. The token of another provider, of another account or of an API user answers `401` : `Invalid token provided in 'x-am-user-authorization' header.`, even when that table has a person with the same username and password.
- Your other admin user accounts accept the token too when the root setting **Allow API Maker User's Token Across Admin Users** is on (`Root Settings → Deployment Settings → Security`) : the account serving the request needs a provider of the same name, the token must still be valid in the account which made it, and both users tables must keep the same password for that username. The person of the request is the row of the account serving it, with its own groups ; a refresh is asked of the account which made the token.
- A call without the token answers `401` : `Please provide 'x-am-user-authorization' token in request headers.` A token whose person is not in the table any more : `401`, `Token user not found in 'mongodb' -> 'shop' -> 'users'.`

## 3. Sign in

**POST /api/system-api/admin/token**

```json
{ "name": "users_tg", "u": "alice@acme.com", "p": "PASSWORD" }
```

**Answer**

```json
{ "success": true, "statusCode": 200, "data": { "token": "eyJ…", "refresh_token": "eyJ…", "expires_in": 259200 } }
```

- The app sends the token in `x-am-user-authorization`, next to `x-am-authorization` of the API user. The sample custom API `/default/login` of a new account gets both in one call.
- The person may call an API when a group of theirs grants it **and** a group of the API user grants it.
- The token holds the columns of the person the provider reads (a column called `name` included, as the person has it), the password fingerprint or the password changed at value, and two fields of its own : `__amTokenGenerator`, the provider which made it, and `__amAdminUserId`, the account of that provider. A refresh needs the `refresh_token` of the same provider.

## The Fields Generator

- The **Fields Generator** tab of a DB provider is a function which returns extra fields to put in the token, from the row of the person (`g.req.body`) : a display name, a department… They come back in `g.req.auth.authAMDB` on every call without a lookup.
- It runs in the sandbox, or on the native process with `runOnNativeProcess: true` (a **Native** chip on the list ; use `g.logger` there, not `console.log`).

## Custom providers

- A **Custom** provider is your own logic : a **token generator** function which answers the token API for `{ "name": "<provider>", … }` with whatever it returns, and a **token validator** function which receives `g.req.body.token` and returns a truthy value (or an object) when the token is valid. Calls send that token in `x-custom-authorization` and your code reads the result in `g.req.auth.authCustom`. [Example](https://docs.apimaker.dev/v1/examples/req/auth/authCustom.html).

## Related

- [Handle role based permissions](https://docs.apimaker.dev/v1/docs/authorization/handle-role-based-permissions.html) · [API group permissions](https://docs.apimaker.dev/v1/docs/apis-security/api-group-permission.html) · [Multi-tenant users](https://docs.apimaker.dev/v1/docs/features/multi-tenant.html#users-of-a-tenant) · [Custom API example](https://docs.apimaker.dev/v1/examples/req/auth/authAMDB.html)
