Connecting web applications to OpenBao through two approaches: direct integration with the REST API and programming language client libraries using AppRole, or indirect integration by injecting secrets into the environment without changing source code.

So far all the discussion has centered on the OpenBao server: engines, policies, auth methods, and leases. Episode 10 brings secrets out of the server and into the web applications that actually use them — Node.js, Go, Python, and Laravel. There are two main paths: direct integration where application code requests secrets itself, and indirect integration where secrets are injected from outside. You will see that both have their place.
Before going into detail, compare the two approaches:
| Aspect | Direct Integration | Indirect Integration |
|---|---|---|
| Source code changes | Required | Not required |
| Secret source | REST API / client library | Environment / file |
| Application control | Full, dynamic | Limited, static at startup |
| Token management | Application holds the token | External party (agent or deploy) |
| Best for | New applications, microservices | Legacy applications, need speed to be secure |
Direct integration gives full flexibility — the application can fetch secrets at any time, even right before use. Indirect integration solves the problem quickly without touching code, but secrets are only populated once when the process starts.
At its core, OpenBao is an HTTP server. Every interaction can be done through the REST API with endpoints prefixed http://127.0.0.1:8200/v1/ and the token sent via the X-Vault-Token header. Example of reading a secret:
curl --header "X-Vault-Token: s.xxxxx" \
http://127.0.0.1:8200/v1/secret/data/appThe complete flow: the application logs in (for example via AppRole) to get a token, then uses that token in the X-Vault-Token header on every request. The secret value is returned as JSON — easy to parse in any language. curl --header "X-Vault-Token: s.xxxxx" http://127.0.0.1:8200/v1/secret/data/app is the heart of direct integration.
Rather than hand-crafting raw HTTP requests, most languages have client libraries that hide the REST API behind simple functions:
| Language | Library |
|---|---|
| Node.js | node-vault or the official Vault JavaScript client |
| Go | github.com/hashicorp/vault/api |
| Python | hvac |
| Laravel (PHP) | hashicorp/vault-php or the direct REST API |
A short example using node-vault in Node.js:
const vault = require("node-vault")({
endpoint: "http://127.0.0.1:8200",
token: "s.xxxxx"
});
const result = await vault.read("secret/data/app");
console.log(result.data.data);The same pattern applies in Go with vault.NewClient, in Python with an hvac.Client session, and in Laravel via a service provider wrapping hashicorp/vault-php. Behind the scenes, all of these clients call the same REST API — so the concepts of X-Vault-Token and v1/... paths still apply.
Because applications have no human to log in with, the AppRole credentials from episode 8 are the standard choice. The sequence:
bao write auth/approle/login \
role_id="9c1f..." \
secret_id="d4a8..."The login response contains a token whose TTL is set by the role (token_ttl). The application stores that token in memory, uses it to read secrets, and refreshes it before the TTL expires. The AppRole plus client library combination is the most common pattern for microservices — and it is a full example of direct integration.
Sometimes the application cannot be changed — whether it is legacy, closed-source, or the team simply doesn't have time. For this case, injecting secrets into the environment is the answer. The principle is simple: secrets are fetched from OpenBao outside the application, then injected as environment variables or a file when the application starts.
Example of an injection result into a .env file:
DB_USER=postgres
DB_PASSWORD=hVt3-9xK2mP
API_KEY=zlQ7-wR4bNc1The application only needs to read process.env.DB_PASSWORD or getenv("DB_USER") as usual — it never knows OpenBao exists. This path is used by deployment tools, init scripts, orchestrators, and (as we will see in the next episode) the OpenBao Agent.
Note
Environment injection solves "where do secrets come from", but not yet "who keeps secrets fresh". Injected secrets stay alive until the process is restarted — for automatic rotation, the next step is the agent you will learn about in episode 11.
The two paths are not a competition — they complement each other and are chosen based on conditions:
The simple guideline: the more dynamic the secret needs, the more worthwhile direct integration; the more legacy applications there are, the more sense the indirect path makes.
In this episode 10 you connected web applications to OpenBao through two paths: direct integration using the v1/... REST API with the X-Vault-Token header and client libraries for Node.js, Go, Python, and Laravel via AppRole; and indirect integration that injects secrets into the environment without touching source code.
Key takeaways:
v1/... endpoints.In the next episode, episode 11, that layer arrives: the OpenBao Agent — a daemon that logs in on its own, renews tokens, and renders application configuration files automatically through templates.