gRPC "UNAUTHENTICATED" in CI
gRPC status 16 UNAUTHENTICATED means the server could not authenticate the caller: the auth metadata (bearer token, API key) was absent, malformed, or expired. It is an identity failure, not a permission one.
What this error means
A call fails with "16 UNAUTHENTICATED: ..." (for example "missing authorization metadata" or "invalid token") in CI, usually because the test client did not attach the secret.
Error: 16 UNAUTHENTICATED: Request had invalid authentication credentials.
Expected OAuth 2 access token, ... metadata: authorization=...Common causes
No auth metadata attached to the call
The CI test client did not add an authorization entry to the request metadata, so the server rejects the unauthenticated call.
An expired or wrong-environment token
The token in CI is stale, for a different environment, or not injected from a secret, so authentication fails.
How to fix it
Attach valid credentials in metadata
- Add an authorization entry to the call metadata.
- Source the token from a CI secret, not a committed file.
- Confirm it is valid for the environment the tests target.
const meta = new grpc.Metadata();
meta.add('authorization', `Bearer ${process.env.GRPC_TOKEN}`);
client.getUser({ id: '1' }, meta, cb);Verify the token out of band
Send an authenticated call with grpcurl to confirm the token itself works before debugging the client.
grpcurl -H "authorization: Bearer $GRPC_TOKEN" \
-plaintext localhost:50051 users.v1.UserService/GetUserHow to prevent it
- Inject auth tokens from CI secrets into request metadata.
- Rotate and refresh tokens so CI never uses an expired one.
- Distinguish UNAUTHENTICATED (identity) from PERMISSION_DENIED (access) when debugging.