# API Keys and Service Accounts — Authentication & Authorization

Source: https://www.skillbyai.com/en/authentication/x-machine

> Credentials for software, not people.

## Managing machine credentials

**API keys** identify a calling application. Generate them with a CSPRNG, show them **once**, and store only a **hash** (a fast hash is acceptable because keys are long and random). A visible **prefix** (for example `sk_live_` style) helps users and secret scanners recognise leaked keys. Scope each key to specific permissions and, where possible, IPs or environments; support **multiple active keys** so customers can **rotate** without downtime; record `last_used_at` and revoke unused keys. **Service accounts** are non-human identities inside your platform; prefer **short-lived credentials** issued from workload identity (cloud IAM roles, Kubernetes service account tokens, OIDC federation from CI) over long-lived static secrets. Keep secrets in a secrets manager, never in source control.

## Issuing and checking API keys

Node.js; the prefix and id let you look up the key without scanning hashes.

```typescript
export async function createApiKey(accountId: string, scopes: string[]) {
  const id = crypto.randomBytes(6).toString('hex');
  const secret = crypto.randomBytes(32).toString('base64url');
  await db.apiKeys.insert({ id, accountId, scopes, secretHash: sha256(secret), createdAt: new Date() });
  return `ak_${id}_${secret}`; // shown to the user once, never stored in plain text
}

export async function apiKeyAuth(req: Request, res: Response, next: NextFunction) {
  const m = /^ak_([0-9a-f]{12})_([A-Za-z0-9_-]+)$/.exec(req.get('x-api-key') ?? '');
  const key = m && (await db.apiKeys.findActive(m[1]));
  const ok = key && crypto.timingSafeEqual(Buffer.from(key.secretHash), Buffer.from(sha256(m![2])));
  if (!ok) return res.status(401).end();
  await db.apiKeys.touch(key.id);                   // last_used_at
  req.client = { accountId: key.accountId, scopes: key.scopes };
  next();
}
```

## Turn on secret scanning

Distinctive key prefixes let platforms such as GitHub secret scanning detect leaked keys in repositories. Have a documented process to revoke and reissue quickly when that happens.

**Quiz:** How should a server store API keys it has issued?

- [ ] Encrypted in the client's browser storage
- [ ] In plain text so support can read them back
- [x] As hashes, showing the plaintext key to the user only once
- [ ] Inside the JWT payload of every response

*Answer:* As hashes, showing the plaintext key to the user only once. A database leak should not reveal working keys.
