Infisical Integration Guide

Technology: infisical · Category: tooling · Last reviewed: 2026-08-23

Source: https://tech-stack.codeamanilabs.org/guide/infisical

Insight:

Infisical centralizes secrets so you stop scattering keys across .env.local files — a Machine Identity fetches them at runtime, leaving only two bootstrap secrets behind. Open-source and self-hostable (data residency for KDPA), and infisical scan in CI catches leaked keys before they ship.

██╗███╗   ██╗███████╗██╗███████╗██╗ ██████╗ █████╗ ██╗
██║████╗  ██║██╔════╝██║██╔════╝██║██╔════╝██╔══██╗██║
██║██╔██╗ ██║█████╗  ██║███████╗██║██║     ███████║██║
██║██║╚██╗██║██╔══╝  ██║╚════██║██║██║     ██╔══██║██║
██║██║ ╚████║██║     ██║███████║██║╚██████╗██║  ██║███████╗
╚═╝╚═╝  ╚═══╝╚═╝     ╚═╝╚══════╝╚═╝ ╚═════╝╚═╝  ╚═╝╚══════╝

Infisical Integration Guide

Focus: Centralize codeAmani's secrets (Anthropic/Gemini keys, Daraja/M-Pesa creds, DB URLs) in one open-source, self-hostable platform instead of scattered .env.local files. Fetch at runtime via a Machine Identity, inject locally with infisical run, and catch leaks before they ship with infisical scan.

Overview

Infisical is an open-source secret-management platform. It replaces ad-hoc .env sprawl with a single source of truth organized by project → environment → folder path. Three ways codeAmani uses it:

Auth uses a Machine Identity + Universal Auth: exchange a clientId/clientSecret for a short-lived token. Those two bootstrap secrets are the only thing that still lives in .env.local / Vercel env — everything else moves into Infisical.

Here is the core idea at a glance — your app carries only two bootstrap secrets and fetches the rest at runtime:

flowchart LR
  A["App at runtime"] -->|"clientId + clientSecret<br/>from .env.local"| B["Machine Identity<br/>Universal Auth"]
  B -->|"short-lived token"| C["Infisical platform<br/>project · environment · path"]
  C -->|"secret value"| A
  A -->|"uses key"| D["Anthropic · Daraja<br/>Supabase · Cloudflare"]

Official Documentation

Resource URL
Getting started https://infisical.com/docs/documentation/getting-started/introduction
Node SDK https://infisical.com/docs/sdks/languages/node
CLI overview https://infisical.com/docs/cli/overview
Universal Auth (machine identity) https://infisical.com/docs/documentation/platform/identities/universal-auth
GitHub (self-host) https://github.com/Infisical/infisical

1. Bootstrap credentials

Create a Machine Identity in the Infisical dashboard, attach it to your project, and copy its Universal Auth clientId + clientSecret. These two are the bootstrap secrets:

INFISICAL_CLIENT_ID=...        # the ONLY secrets that stay in .env.local / Vercel env
INFISICAL_CLIENT_SECRET=...

2. SDK — fetch secrets at runtime (Node)

npm install @infisical/sdk    # current major is v5.x (from the node-sdk-v2 repo)
import { InfisicalSDK } from "@infisical/sdk";

// Cloud default; pass { siteUrl } for a self-hosted instance
const client = new InfisicalSDK();

await client.auth().universalAuth.login({
  clientId: process.env.INFISICAL_CLIENT_ID!,
  clientSecret: process.env.INFISICAL_CLIENT_SECRET!,
});

const secret = await client.secrets().getSecret({
  secretName: "DARAJA_CONSUMER_SECRET",
  projectId: "proj_abc123",
  environment: "production",
  secretPath: "/mpesa",          // optional folder
  expandSecretReferences: true,
});
console.log(secret.secretValue);

getSecret throws on a missing key (StatusCode=404 Secret not found) — handle it rather than silently falling back, so a misconfigured environment fails loudly at startup.

SDK v5 note: getSecret / listSecrets accept viewSecretValue (default true). If you pass viewSecretValue: false, secretValue comes back masked as <hidden-by-infisical> — leave it at the default when you actually need the value.

3. CLI — local dev + leak scanning

The CLI gives you two wins — secrets injected into dev without ever touching disk, and a scanner that catches leaks before they ship:

flowchart TD
  A["infisical login + init<br/>links repo to project · env"] --> B["infisical run -- npm run dev"]
  B -->|"inject as env vars<br/>nothing written to disk"| C["dev server child process"]
  A --> D["infisical scan"]
  D --> E{"Leaked secret in<br/>code or git history?"}
  E -->|"yes"| F["fail pre-commit · CI"]
  E -->|"no"| G["safe to ship"]
npm install -g @infisical/cli
infisical login          # interactive
infisical init           # link the repo to a project/environment

# Inject secrets as env vars into the dev server (nothing written to disk):
infisical run -- npm run dev

# Pre-commit / CI: scan code + git history for leaked secrets
infisical scan

4. CI/CD — secrets in GitHub Actions

In CI you don't run infisical login interactively — instead the official Infisical/secrets-action authenticates a Machine Identity and injects the project's secrets into the job as env vars. Store only the two bootstrap values (client-id/client-secret) as GitHub Actions secrets; everything else stays in Infisical.

flowchart LR
  A["GitHub Actions job"] -->|"client-id + client-secret<br/>from GH secrets"| B["Infisical secrets-action<br/>Universal Auth"]
  B -->|"short-lived token"| C["Infisical platform<br/>project · env · path"]
  C -->|"export-type env"| D["secrets as env vars<br/>in later steps"]
  D --> E["build · deploy · migrate"]
# .github/workflows/deploy.yml
name: Deploy

on:
  push:
    branches: [main]

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      # Authenticate via Machine Identity (Universal Auth) and inject secrets
      # as env vars for every subsequent step in this job.
      - uses: Infisical/secrets-action@v1.0.16
        with:
          method: "universal"                              # default
          client-id: ${{ secrets.INFISICAL_CLIENT_ID }}    # the only two GH secrets you need
          client-secret: ${{ secrets.INFISICAL_CLIENT_SECRET }}
          project-slug: "your-project-slug"
          env-slug: "production"                            # dev | staging | production
          secret-path: "/"                                 # default; e.g. "/mpesa"
          domain: "https://app.infisical.com"              # change for a self-hosted instance

      # Secrets are now plain env vars — reference them like any other.
      - name: Deploy
        run: |
          echo "Deploying with DARAJA_CONSUMER_KEY=${DARAJA_CONSUMER_KEY:+set}"
          npm run deploy

Inputs above are the verified Universal Auth keys; export-type defaults to env. Set export-type: file (with file-output-path) instead if a step needs an on-disk .env. OIDC (method: oidc, identity-id) is also supported and removes the long-lived client-secret entirely — prefer it once your CI provider trust is configured.

Gotcha — least-privilege identity scope: create a separate Machine Identity per environment and grant it read-only access to only the project/path that workflow needs (e.g. the production env at /). A CI identity scoped to every project becomes a single key that can exfiltrate your entire secret store if the client-secret GH secret leaks. Rotate the client-secret on a schedule and keep the identity off any path it doesn't read.

codeAmani notes

Official docs: