# Secrets

> The secret of an API Maker account - hashing and encryption keys, the transfer key shared with apps, API user passwords, connection strings, default auth providers, multi-tenant entries - a TypeScript object kept encrypted on the server and never in Git.

Source: https://docs.apimaker.dev/v4/docs/secrets/secrets.html

A secret holds what must never be in the code : keys, passwords, connection strings. Every account gets one at creation, the **default secret**, and can add more. Code reads them with [get secret](https://docs.apimaker.dev/v4/docs/apis-all/system-apis/system-generated-get-secret-by-name-api.html) ; instances pick their connection string from them ; conversions and system APIs use their keys.

| | |
|---|---|
| Page | `Security → Secret Management` : the secrets of the account, one of them the default. |
| Shape | A TypeScript file which exports an object. `common` is read by API Maker ; add your own sections next to it. |
| Kept | Encrypted on the server of this environment. Never pushed to Git : each environment has its own values. |
| Another secret | Every request uses the default secret. Your code reads another secret of the account by its name : `getSecret(keys, fromSecretName)`. |

## The default secret of a new account

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

let Secret: T.ISecretType | any = {
    common: <T.ISecretTypeCommon>{
        hashingAlgorithm: 'SHA256',              // the hashing conversion and the hash data API
        nonce: '85491cec-…',                     // key of the hashes ; without it, secret is used

        encryptionAlgorithm: 'AES',              // the encryption conversion of the schemas
        secret: '1eaaca38-…',                    // never change it once data is encrypted with it

        encryptionAlgorithmFETransfer: 'AES',    // encrypt and decrypt data system APIs
        secretFETransfer: '78e493ee-…',          // shared with your frontend or mobile app
        feTransferDataValidityInSeconds: 300,    // an encrypted payload older than this is refused

        apiUserPasswords: {                      // API users can read their password from a path of the secret
            default: '12345',
        },

        connectionString: {                      // offered when you add an instance
            mongodb: 'mongodb://your_username:your_password@server_ip:27017/?authSource=admin&replicaSet=rs0&directConnection=true',
            mysql_8: 'mysql://your_username:your_password@server_ip:server_port?multipleStatements=true',
            mariadb: 'mariadb://your_username:your_password@server_ip:server_port?multipleStatements=true',
            sqlServer: 'Server=server_ip;User Id=user_id;Password=your_password;Trusted_Connection=True;TrustServerCertificate=True;',
            postgresql: 'postgresql://your_username:your_password@server_ip:server_port',
            oracle: 'server_ip:server_port/oracle_process_name',
            oracle_username: 'your_username',
            oracle_password: 'your_password',
        },

        // authProviders: <string[]>[],           // the auth providers every API needs unless its settings say otherwise
    },
};
module.exports = Secret;
```

## The keys of `common`

| Key | Used by |
|---|---|
| `hashingAlgorithm`, `nonce` | The `hashing` conversion of a [schema](https://docs.apimaker.dev/v4/docs/schema/schema.html#3-conversions-clean-the-value-first) and the [hash data](https://docs.apimaker.dev/v4/docs/apis-all/system-apis/system-generated-hash-data-api.html) API. `SHA256` is the algorithm supported. Without `nonce`, `secret` is the key. |
| `encryptionAlgorithm`, `secret` | The `encryption` conversion : `AES`. `RC4` and `TRIPLEDES` are legacy ciphers, kept to read the data of API Maker 3 : do not choose them for new data. Changing `secret` means re-encrypting every encrypted value, and re-hashing when there was no nonce. |
| `encryptionAlgorithmFETransfer`, `secretFETransfer` | The [encrypt](https://docs.apimaker.dev/v4/docs/apis-all/system-apis/system-generated-encrypt-data-api.html) and [decrypt](https://docs.apimaker.dev/v4/docs/apis-all/system-apis/system-generated-decrypt-data-api.html) APIs, the [encrypted payloads](https://docs.apimaker.dev/v4/docs/features/security-features.html#encrypted-request-payloads) and the encrypted answers. This is the key you give to your apps. |
| `feTransferDataValidityInSeconds` | How old an encrypted payload may be. |
| `apiUserPasswords` | Passwords an [API user](https://docs.apimaker.dev/v4/docs/apis-security/api-user-permission.html) reads by path (`common.apiUserPasswords.default`), so the password is not in Git. |
| `connectionString` | The list offered by the instance form. Any key of the secret can hold one ; this section is a convention. |
| `authProviders` | The names of the [auth providers](https://docs.apimaker.dev/v4/docs/authorization/AMDB.html) every API needs by default. Absent : only the API user token. The settings of an API, a table or a database override it. |
| `multiTenant` | The tenants tables of [multi-tenant](https://docs.apimaker.dev/v4/docs/features/multi-tenant.html#2-point-the-default-secret-to-that-table) instances. |

## Your own keys

**TypeScript**

**Read them from code**

```typescript
const apiKey = await g.sys.system.getSecret('stripe.apiKey');
const [ key, cs ] = await g.sys.system.getSecret([ 'stripe.apiKey', 'common.connectionString.mysql_8' ]);
```

**Python**

**Read them from code**

```python
api_key = await g.sys.system.get_secret('stripe.apiKey')
key, cs = await g.sys.system.get_secrets(['stripe.apiKey', 'common.connectionString.mysql_8'])
```

**PHP**

**Read them from code**

```php
$apiKey = $g->sys->system->getSecret('stripe.apiKey');
[$key, $cs] = $g->sys->system->getSecrets(['stripe.apiKey', 'common.connectionString.mysql_8']);
```

**C#**

**Read them from code**

```csharp
var apiKey = await g.Sys.System.GetSecret("stripe.apiKey");
var both = await g.Sys.System.GetSecrets(["stripe.apiKey", "common.connectionString.mysql_8"]);
var (key, cs) = (both[0], both[1]);
```

**Go**

**Read them from code**

```go
apiKey, err := g.Sys.System.GetSecret("stripe.apiKey")
if err != nil {
	return nil, err
}
both, err := g.Sys.System.GetSecrets([]string{"stripe.apiKey", "common.connectionString.mysql_8"})
if err != nil {
	return nil, err
}
key, cs := both[0], both[1]
```

**Rust**

**Read them from code**

```rust
let api_key = g.sys.system.get_secret("stripe.apiKey", None)?;
let both = g.sys.system.get_secrets(&["stripe.apiKey", "common.connectionString.mysql_8"], None)?;
let (key, cs) = (&both[0], &both[1]);
```

**Java**

**Read them from code**

```java
Object apiKey = g.sys.system.getSecret("stripe.apiKey");
List<Object> both = g.sys.system.getSecrets(List.of("stripe.apiKey", "common.connectionString.mysql_8"));
Object key = both.get(0), cs = both.get(1);
```

**Kotlin**

**Read them from code**

```kotlin
val apiKey = g.sys.system.getSecret("stripe.apiKey")
val (key, cs) = g.sys.system.getSecrets(listOf("stripe.apiKey", "common.connectionString.mysql_8"))
```

- Add sections freely : `stripe: { apiKey: '…' }`. A path with dots reaches any key.
- A team keeps one secret per environment with the same keys and other values : the code does not change between a laptop and production.

## Related

- [Security features](https://docs.apimaker.dev/v4/docs/features/security-features.html) · [Connection strings](https://docs.apimaker.dev/v4/docs/Database-connection-string/mongodb-connection-strings.html) · [Get secret API](https://docs.apimaker.dev/v4/docs/apis-all/system-apis/system-generated-get-secret-by-name-api.html) · [Git integration](https://docs.apimaker.dev/v4/docs/Git/git.html)
