An open API service indexing awesome lists of open source software.

https://github.com/tetherto/svc-facs-auth


https://github.com/tetherto/svc-facs-auth

Last synced: about 2 months ago
JSON representation

Awesome Lists containing this project

README

          

# svc-facs-auth

This is a facility to handle user authentivcaton that extends from `bfx-facs-base` to provide authentication management with support for generating and validating tokens, managing users, and handling permissions. It uses SQLite for storing user and token information and LRU for caching.

## Configuration

This facility requires a config file in the following structure:

```javascript
{
"a0": {
"superAdmin": "superadmin@localhost", // Superadmin email address
"ttl": 5000, // Default token time-to-live in seconds
"saltRounds": 10, // Number of salt rounds for password hashing
"trustProxy": false, // See "Client IP resolution" below
"roles": { // Roles with associated permissions
"admin": [
"miner:rw",
"container:rw",
"user:rw"
],
"site_manager": [
"miner:rw",
"container:rw",
"user:r"
],
"user": ["jobs:rw"]
}
}
}
```

### Client IP resolution

Tokens are bound to the IPs observed at issue time. By default the facility
trusts only the direct socket peer (`req.socket.remoteAddress`) and ignores
the spoofable `X-Forwarded-For` header — so callers behind a proxy will see
their token bound to the proxy's address.

If your service runs behind a trusted reverse proxy, set `trustProxy: true`
**and** configure your HTTP framework to validate the proxy chain itself
(e.g. Express's `app.set('trust proxy', …)`). When enabled, the facility:
- Checks for Cloudflare's `CF-Connecting-IP` header (if present and valid)
- Trusts the framework-derived `req.ip` / `req.ips` (from `X-Forwarded-For`)
- Always includes `req.socket.remoteAddress` as a fallback

The raw `X-Forwarded-For` header is never consumed directly for security reasons.

### Roles

`createUser` and `updateUser` only accept role names declared as keys in
`conf.roles`. The super-admin marker (`*`) cannot be assigned via these
APIs — it is reserved for the bootstrap super-admin written by `_initDb`.
`updateUser` additionally requires the caller's token to hold `user:rw`
whenever the requested roles differ from the user's current roles.

## Documentation
### `auth.createUser(req)`
Creates a new user with specified roles and permissions.

**Parameters:**
- `req`: Object with user creation details.
- `email`: Email address of the user.
- `roles`: Array of roles for the user.
- `password`: Password for the user.

```javascript
const result = await auth.createUser({
email: 'user@example.com',
roles: ['admin']
})
```

### `auth.updateUser(req)`
Updates an existing user with new roles and permissions.

**Parameters:**
- `req`: Object with user update details.
- `token`: Authentication token for the user.
- `email`: Email address of the user.
- `roles`: Array of roles for the user.
- `password`: New password for the user.

```javascript
const result = await auth.updateUser({
token: 'some-token',
email: 'new@example.com',
roles: ['admin']
})
```

### `auth.compareUser(req)`
Compares user details (email, password, roles) with the stored user information.

**Parameters:**
- `req`: Object containing user details for comparison.
- `token`: Authentication token for the user.
- `email (optional)`: Email address to compare.
- `roles (optional)`: Array of roles to compare.
- `password (optional)`: Password to compare.

```javascript
const isMatching = await auth.compareUser({
token: 'user-token',
email: 'test@example.com',
roles: ['user'],
password: 'securepassword'
})
console.log(isMatching) // true or false
```

### `auth.genToken(req)`
Generates a new authentication token based on the provided parameters. It validates the input, allocates resources, and stores the token data.

**Parameters:**
- `req`: Object containing token generation details.
- `ips`: List of IP addresses associated with the token.
- `userId`: User ID for whom the token is generated.
- `ttl`: Time-to-live for the token in seconds (default: 300).
- `metadata`: Optional metadata associated with the token.
- `pfx`: Prefix for the token (default: 'pub').
- `scope`: Scope for the token (default: 'api').
- `roles`: Array of roles for the token.

```javascript
const token = await auth.genToken({
ips: ['192.168.1.1'],
userId: 1,
ttl: 3600,
metadata: { key: 'value' },
pfx: 'pub',
scope: 'api',
roles: ['admin']
})
```

### `auth.regenerateToken(req)`
Regenerates an existing authentication token. It validates the old token, checks permissions, and creates a new token.

**Parameters:**
- `req`: Object with token regeneration details.
- `oldToken`: Existing token to be regenerated.
- `ips`: New IP addresses associated with the token (optional).
- `ttl`: Time-to-live for the new token in seconds (default: 300).
- `pfx`: Prefix for the new token (default: 'pub').
- `scope`: Scope for the new token (default: 'api').
- `roles`: Array of roles for the new token.

```javascript
const newToken = await auth.regenerateToken({
oldToken: 'existing-token',
ips: ['192.168.1.1'],
ttl: 3600,
pfx: 'pub',
scope: 'api',
roles: ['admin']
})
```

### `auth.getTokenPerms(token)`
Retrieves permissions associated with a token.

**Parameters:**
- `token`: The token to get permissions for.

**Returns:**
- `{ superadmin: , perms: }` with token permissions.

```javascript
const perms = auth.getTokenPerms('some-token')
console.log('Token permissions:', perms)
```

### `auth.resolveToken(token, ips)`
Validates a token and checks if it is associated with the given IP addresses.

**Parameters:**
- `token`: The token to resolve.
- `ips`: List of IP addresses to validate.

```javascript
const user = await auth.resolveToken('some-token', ['192.168.1.1'])
```
Note: User data (`user`) is coming from the `auth_token` table.

### `auth.tokenHasPerms(token, perm)`
Checks if a token has the required permissions.

**Parameters:**
- `token`: The token to check.
- `perm`: Permission to check.

**Returns:**
- `true` if the token has the required permissions.
- `false` otherwise.

```javascript
const hasPerms = auth.tokenHasPerms('some-token', 'miner:r')
console.log('Token has required permissions:', hasPerms)
```

### `auth.cleanupTokens()`
Cleans up expired tokens from the database.

```javascript
await auth.cleanupTokens()
```

### `auth.addHandlers(handlers)`
Adds authentication handlers to the service.

**Parameters:**
- `handlers`: Object containing authentication handlers, each key is a handler name and value is a handler function.

```javascript
auth.addHandlers({
'handler-name': async (ctx, req) => {
// Handler logic
}
})
```

### `auth.authCallbackHandler(type, req)`
Handles authentication callbacks by resolving tokens and returning authentication results.

**Parameters:**
- `type`: Type of authentication callback.
- `req`: Request object containing callback details.

```javascript
const token = await auth.authCallbackHandler('callback-type', request)
```

### `auth.getUserById(id)`
Return the user with the given id

**Parameters:**
- `id`: id of the user.

```javascript
const user = await auth.getUserById('3')
```

### `auth.getUserByEmail(email)`
Return the user with the given email

**Parameters:**
- `id`: email of the user.

```javascript
const user = await auth.getUserByEmail('new@example.com')
```

### `auth.listUsers()`
Returns a list of users present

```javascript
const users = await auth.listUsers('callback-type', request)
```

### `auth.deleteUser(id)`
Deletes the user with the provided id.

**Parameters:**
- `id`: id of the user.

```javascript
await auth.deleteUser('23')
```

### `auth.mfaHandler(type, req)`
Handles multi-factor authentication (MFA) by invoking the specified MFA handler.

**Parameters:**
- `type`: The type/name of the MFA handler to invoke (e.g., `'totp'`).
- `req`: The request object containing necessary authentication details.

**Throws:**
- `ERR_HANDLER_INVALID` if the specified handler does not exist or is not a function.

```javascript
const result = await auth.mfaHandler('totp', { totp: '123456' , ... })
```

### `auth.mfaCallbackHandler(type, req, getUserMfaMethods)`
Handles authentication callbacks with MFA support. If MFA is required, returns a CSRF token and the list of required MFA methods; otherwise, returns the authentication token.

**Parameters:**
- `type`: The type of authentication callback.
- `req`: The request object containing callback details.
- `getUserMfaMethods`: A function that returns the list of enabled MFA methods for the user.

**Returns:**
- If MFA is required:
An object containing `csrf_token`, `mfa_required: true`, and `mfa_methods` (array of enabled MFA methods).
- If MFA is not required:
An object containing the authentication `token`.

**Throws:**
- `ERR_MFA_METHOD_HANDLER_INVALID` if getUserMfaMethods is not a function.