Skip to content
Français
Account: not signed in, sync available My learning
Select theme
Français

Vault authentication: userpass and AppRole

By updated

Improve this page

HashiCorp Vault logo

Before accessing a secret in Vault, a client must prove its identity. Vault offers several authentication methods (plugins that verify an identity) depending on the context: human users, applications, CI/CD pipelines, cloud workloads. A successful login returns a token, a credential the client then presents on every request.

This guide covers the two most common methods:

  • userpass: username/password authentication (for users)
  • AppRole: authentication for applications and CI/CD

What you will learn

  • Enable an authentication method and create a userpass account
  • Configure an AppRole role with a role_id and a single-use secret_id
  • Integrate authentication into a CI/CD pipeline without exposing a long-lived secret
  • Protect the distribution of the secret_id with response wrapping
  • Diagnose the most common authentication refusals
  • SOCLE anchoring: this lesson implements SOCLE-SEC-STO-3 (in French), accesses scoped to the strict minimum and separated by environment, and SOCLE-SEC-ROT-2 (in French), short-lived identities rather than long-lived secrets

Prerequisites

This lesson is the third of the module, after storing secrets with KV v2. You need a Vault server that is installed and running, plus administrator access (the root token, the all-powerful credential issued at initialization, or an admin policy) to enable methods and create accounts.

Authenticating does not by itself grant any right on a secret: the login produces a token, and it is the policy attached to that token that says what it may read. A policy is a set of rules that allows or denies operations on given paths (the addresses under which Vault exposes its data and its functions). Policies are the subject of the next lesson. The names dev-policy and webapp-policy used here are defined there; until then, read them as plain labels.

How does userpass authentication work?

The userpass method is simple: username + password. It suits developers who access Vault through the CLI or the UI.

How do I enable userpass?

No authentication method is active at installation, except the token method. Enabling userpass creates a new backend at the path auth/userpass/: it is this path, not the name of the method, that you will find in every command and in the policies. Remember it, because a mistyped path gives the no handler for route error (HTTP 404 with a token, measured on Vault 2.2.0; the code changes without a token, see the troubleshooting section at the end of the page).

Terminal window
vault auth enable userpass

Output:

Success! Enabled userpass auth method at: userpass/

How do I create a user?

Creating an account is a simple write under auth/userpass/users/, the last segment of the path becoming the username. Two reflexes from now on: never type the password in clear text in the shell history (prefer an environment variable or interactive input), and always assign an explicit policy, otherwise the account inherits only default and cannot read any business secret.

Terminal window
vault write auth/userpass/users/alice \
password=@/path/to/alice-password \
policies="dev-policy"

The @ prefix tells the CLI to read the value from a file: the password therefore appears neither in the command nor in the shell history. Create this file with 0600 permissions and delete it once the account is created.

How does a user log in?

The user alice can now log in. The command contains no password=: the CLI then asks for the password at the keyboard, without displaying it or keeping it in the shell history.

Terminal window
vault login -method=userpass username=alice

Output:

Success! You are now authenticated.
Key Value
--- -----
token hvs.CAESICpTptPYxzwJISnFYQQRZzz7ftYL...
token_accessor ORgCVUVANPcCkzgF8oKs9ZRc
token_duration 768h
token_renewable true
token_policies ["default" "dev-policy"]
identity_policies []
policies ["default" "dev-policy"]
token_meta_username alice

The returned token is automatically stored in ~/.vault-token for the following commands. The token and accessor change at every login; the 768h duration (32 days) is what a userpass token gets by default, measured on Vault 2.2.0.

How do I manage users?

These four commands cover the complete lifecycle of an account. One trap deserves a mention: vault write replaces the fields you provide without touching the others, so rewriting the policies does not change the password, and the other way round. Also know that deleting a user does not revoke the tokens already issued in their name; to cut access immediately, you must revoke the tokens through their accessor or revoke the authentication path.

Terminal window
# List the users
vault list auth/userpass/users/
# Change the password
vault write auth/userpass/users/alice password=@/path/to/new-password
# Change the policies
vault write auth/userpass/users/alice policies="dev-policy,staging-readonly"
# Delete a user
vault delete auth/userpass/users/alice

How do I configure the token lifetime?

You can customize the lifetime and behavior of tokens. The token TTL (time-to-live) is how long a token stays valid before it expires; the maximum TTL caps it even when the token is renewed.

Terminal window
vault write auth/userpass/users/bob \
password=@/path/to/bob-password \
policies="dev-policy" \
token_ttl="8h" \
token_max_ttl="24h" \
token_bound_cidrs="10.0.0.0/8"
ParameterDescription
token_ttlInitial lifetime of the token
token_max_ttlMaximum lifetime (even after renewal)
token_bound_cidrsIP ranges allowed to use the token

How does AppRole authentication work for applications and CI/CD?

AppRole is the recommended method for applications and pipelines. It uses two elements:

  • role_id: the identity of the application (stable, like a username)
  • secret_id: a credential designed to be ephemeral (like a temporary password), provided the role bounds it

Why AppRole?

The difference is not about how strong the password is, but about the lifetime of the credential. A userpass password stays valid as long as nobody changes it, so a leak in a build log remains exploitable months later. A secret_id, on the other hand, can be bounded: secret_id_ttl limits how long it stays valid and secret_id_num_uses restricts it to a single use, which shrinks the exploitation window to almost nothing.

These bounds are not automatic, though. On a role created without setting these parameters (measured on Vault 2.2.0), secret_id_ttl is 0s and secret_id_num_uses is 0, which means no limit: the secret_id never expires and stays reusable. The role has to set them, as the example in the section on creating a role does.

UserpassAppRole
Stable passwordsecret_id bounded by the role (lifetime, single use)
Hard to automateDesigned for automation
Password with no expiry and no use limitLimits on number of uses, TTL, CIDR

How do I enable AppRole?

As with userpass, the method is mounted on its own path, auth/approle/. A mount is exactly that: a location where a method (or a secrets engine) is attached. It can coexist without conflict with the other methods already enabled: Vault allows several authentication backends in parallel, each issuing its own tokens with its own policies.

Terminal window
vault auth enable approle

How do I create a role?

An AppRole role describes an application, not a person: it fixes in advance the policies granted and the duration limits. Parameters prefixed with secret_id_ govern the credential, those prefixed with token_ govern the token obtained after login. The policies field accepted below is a historical alias of token_policies, which Vault returns under both names on a vault read auth/approle/role/my-webapp.

Terminal window
vault write auth/approle/role/my-webapp \
secret_id_ttl=10m \
token_num_uses=10 \
token_ttl=20m \
token_max_ttl=30m \
secret_id_num_uses=1 \
policies="webapp-policy"
ParameterDescriptionRecommended value
secret_id_ttlValidity period of the secret_id10-30 minutes
secret_id_num_usesNumber of uses of the secret_id1 (single use)
token_ttlLifetime of the token obtainedAccording to application need
token_num_usesNumber of uses of the token0 (unlimited) or as needed

How do I get the credentials?

The role gives out its two credentials separately: the role_id once, the secret_id on every deployment.

Fetch the role_id

The role_id is stable and can be stored in the application's configuration:

Terminal window
vault read auth/approle/role/my-webapp/role-id

Output:

Key Value
--- -----
role_id d922482a-36c8-45fa-df77-c793b2980f51

Generate a secret_id

The secret_id is designed to be ephemeral: you generate it at each deployment:

Terminal window
vault write -f auth/approle/role/my-webapp/secret-id

Output:

Key Value
--- -----
secret_id aab71b03-aeeb-6965-dd97-73d5f9e30f38
secret_id_accessor 67eabeab-e4b4-12f3-8fde-4ab79b5c7027
secret_id_num_uses 1
secret_id_ttl 10m

How do I log in with AppRole?

The application uses role_id + secret_id to obtain a token:

Terminal window
vault write auth/approle/login \
role_id="d922482a-36c8-45fa-df77-c793b2980f51" \
secret_id="aab71b03-aeeb-6965-dd97-73d5f9e30f38"

Output:

Key Value
--- -----
token hvs.CAESIG...
token_accessor ABC123...
token_duration 20m
token_renewable true
token_policies ["default" "webapp-policy"]

Here is how to integrate AppRole into a CI/CD pipeline:

  1. Pre-deployment: an administrator generates the secret_id and hands it to the pipeline (CI/CD secret variable)

  2. Pipeline: fetches the role_id (stored in config) and the secret_id (secret variable)

  3. Login: the pipeline runs vault write auth/approle/login to obtain a token

  4. Secret access: the pipeline uses the token to read the secrets it needs

  5. End: the token expires automatically

The read path follows the -mount= form taught in the KV v2 lesson, which separates the mount point from the relative path. The script below puts steps 3 and 4 into practice. Three precautions are deliberate: set -euo pipefail stops the job as soon as a command fails rather than carry on with an empty token, -field=token avoids printing the full Vault response in the logs, and the token is never written to disk. Also remember to turn off the runner's command echo (set +x) if your CI enables it by default.

#!/bin/bash
set -euo pipefail
# Environment variables (injected by the CI/CD)
# VAULT_ADDR, VAULT_ROLE_ID, VAULT_SECRET_ID
# Get the token
VAULT_TOKEN=$(vault write -field=token auth/approle/login \
role_id="$VAULT_ROLE_ID" \
secret_id="$VAULT_SECRET_ID")
export VAULT_TOKEN
# Read the secrets
DB_PASSWORD=$(vault kv get -mount=secret -field=password apps/webapp/database)
# Use the secret: passed through the environment, it appears neither in the
# command line visible to ps, nor in the shell history
export PGPASSWORD="$DB_PASSWORD"
psql -h db.internal -U webapp -d webapp -c 'SELECT 1'
echo "Deploying with DB access..."

How does a wrapped secret_id make AppRole safer?

The previous workflow assumes that someone hands the secret_id to the pipeline. To prevent it from travelling in clear text, use response wrapping: Vault places the response in a single-use vault and returns only a short-lived wrapping_token, which serves one time only to retrieve the real value.

Terminal window
# Generate a wrapped secret_id (valid 5 minutes)
vault write -wrap-ttl=5m -f auth/approle/role/my-webapp/secret-id

Output:

Key Value
--- -----
wrapping_token: hvs.CAESIOe9fg2saB1v44rzYlQfct_IGzpgk2n7ZvUUI--jao_m
wrapping_accessor: IRSMBlNVmDshiL3JV3DXck9W
wrapping_token_ttl: 5m
wrapping_token_creation_time: 2026-03-16 14:30:00.413673165 +0000 UTC
wrapping_token_creation_path: auth/approle/role/my-webapp/secret-id
wrapped_accessor: 1ead00ec-0101-5042-7c51-71d6fa953ab4

The secret_id appears nowhere in this output: that is the whole point. Note also that the keys end here with a colon, unlike the other Vault responses, because this block describes the envelope and not the data itself. These formats were replayed on Vault 2.2.0; the identifiers and the date change at every call.

The CI/CD receives a wrapping_token instead of the secret_id. It must "unwrap" it:

Terminal window
VAULT_TOKEN="<wrapping_token>" vault unwrap

The next diagram follows the complete path. Look first at how the administrator never sees the secret_id itself (steps ① and ②), then at how the pipeline receives it by exchanging the wrapping_token (steps ④ and ⑤) before logging in with the role_id (steps ⑥ and ⑦).

Sequence between administrator, CI pipeline and Vault: the administrator asks for a wrapped secret_id and receives only a wrapping_token, which they store as a secret variable of the pipeline. The pipeline exchanges it with Vault for the secret_id, the wrapping_token being consumed, then logs in with role_id and secret_id, receives a short-lived token attached to the role's policies and reads the secret.VaultCI pipelineAdministrator① Asks for a wrapped secret_id (wrap-ttl5m)② Returns a wrapping_token, never thesecret_id③ Stores thewrapping_token as asecret variable④ unwrap with thewrapping_token⑤ Returns thesecret_id, thewrapping_token isconsumed⑥ login with role_idand secret_id⑦ Returns ashort-lived tokenbound to the rolepolicies⑧ Reads the secretwith that token
Source · SVG
Esc to close, + and − to zoom, scroll to move around. 100 %

Userpass, AppRole or token: which method should I choose?

These three methods are not mutually exclusive, they cover different populations on the same Vault cluster. The row to look at first is Renewal: it determines what an attacker can do with a credential recovered from a log or an environment variable. The Token column here means the direct use of a token issued by hand, handy for one-off troubleshooting but whose renewal cannot be automated.

AspectUserpassAppRoleToken
TargetHumansApplicationsSimple automation
EaseVery simpleMediumSimple
SecurityMediumHighLow
RenewalManualAutomatableManual
CI/CDNot recommendedRecommendedAcceptable short-term

Troubleshooting

Vault's error messages are deliberately vague so as not to tell an attacker what exists on the server side: invalid username or password is returned for a nonexistent account as well as for a wrong password. So always start by checking the method's path with vault auth list, before suspecting the credential itself.

The same principle applies to AppRole, with a practical consequence: a nonexistent role_id, a wrong secret_id, an expired secret_id and an already consumed secret_id all return exactly the same message, with the same HTTP code. The client therefore cannot tell these four causes apart from the error; it is the vault administrator who diagnoses, using the commands in the last column. Messages observed on Vault 2.2.0.

The HTTP code for a missing route, however, depends on the call. Measured on Vault 2.2.0 by calling the API directly: with a valid X-Vault-Token header, which is what the CLI sends when VAULT_TOKEN is set, Vault answers 404 and no handler for route; without that header, it answers 403 Forbidden (the text of that 403 was not recorded). Since an application login normally sends no token, a 403 received without a token can therefore hide a method that is not enabled or a mistyped path, and not only a permissions problem.

SymptomLikely causeSolution
invalid username or password (HTTP 400)Nonexistent account or wrong password: Vault does not say whichCheck username/password, then vault auth list for the path
invalid role or secret ID (HTTP 400)Nonexistent role_id, wrong, expired or already consumed secret_id: Vault does not say whichvault read auth/approle/role/<name> to confirm the role exists, then vault read auth/approle/role/<name>/role-id, then generate a new secret_id
no handler for route "auth/..." (HTTP 404 with a token; 403 without a token)Auth method not enabled, or mistyped pathvault auth list, then vault auth enable <method> if it is missing

Key points

  1. userpass: simple, for human users (CLI, UI)
  2. AppRole: secure, for applications and CI/CD
  3. role_id = stable identity, secret_id = ephemeral credential
  4. In production: secret_id_num_uses=1 for single use and a short secret_id_ttl, because by default a secret_id never expires
  5. Response wrapping: extra protection for pipelines
  6. Each user/application = specific policies (least privilege)
  7. Evidence expected for SOCLE-SEC-STO-3 and SOCLE-SEC-ROT-2: accesses scoped to the strict minimum and separated by environment, and short-lived identities (TTL and single use of the secret_id) rather than long-lived secrets

Knowledge check

Check that the essentials of this lesson are in place. The questions only cover what has just been explained here.

Knowledge check

Check what you have learned with this interactive quiz

4 questions
4 min
70% to pass

How it works

  • The timer starts when you click Start
  • Multiple choice, true/false and short answer questions
  • You can move between questions
  • Detailed results are shown at the end

Starts the quiz and the timer

Is this project useful to you?

The guides, courses, quizzes and labs stay free. If you use them regularly, you can contribute to their upkeep and development.

Become a supporting member (new tab) One-time support (new tab) Learn more

Follow the project on LinkedIn