API Authentication
All Teabar API requests require authentication via OIDC access tokens from Keycloak. This guide covers the available authentication methods and best practices.
Authentication Methods
| Method | Use Case | Token Lifetime |
|---|---|---|
| Interactive Login | CLI, local development | Configured in Keycloak (default 15min, auto-refresh) |
| Service Accounts | CI/CD, automation, scripts | Configured per client in Keycloak |
Using Access Tokens
Include the Keycloak access token in the Authorization header:
curl -H "Authorization: Bearer <keycloak-access-token>"
https://api.teabar.dev/teabar.v1.EnvironmentService/ListEnvironments Interactive Authentication
For CLI and interactive use, teactl handles authentication via the OIDC device flow:
teactl auth login The CLI automatically:
- Stores tokens securely in system keychain
- Refreshes tokens before expiry
- Includes tokens in API requests
Service Account Authentication
For CI/CD and automation, use Keycloak service accounts with the client credentials flow.
Getting a Token
# Request token from Keycloak
TOKEN=$(curl -s -X POST
"https://auth.bcp.technology/realms/teabar/protocol/openid-connect/token"
-d "client_id=my-service-account"
-d "client_secret=$CLIENT_SECRET"
-d "grant_type=client_credentials" | jq -r '.access_token')
# Use with teactl
export TEABAR_TOKEN="$TOKEN"
teactl env list
# Or use directly with API
curl -H "Authorization: Bearer $TOKEN"
https://api.teabar.dev/teabar.v1.EnvironmentService/ListEnvironments Note
Device Authorization Flow
For CLI and devices without browsers (used by teactl auth login):
# Step 1: Request device code
curl -X POST "https://auth.bcp.technology/realms/teabar/protocol/openid-connect/auth/device"
-d "client_id=teabar-cli"
# Response
{
"device_code": "ABC123...",
"user_code": "ABCD-1234",
"verification_uri": "https://auth.bcp.technology/realms/teabar/device",
"verification_uri_complete": "https://auth.bcp.technology/realms/teabar/device?user_code=ABCD-1234",
"expires_in": 600,
"interval": 5
} User visits the URL and enters the code, then poll for the token:
# Poll for token
curl -X POST "https://auth.bcp.technology/realms/teabar/protocol/openid-connect/token"
-d "client_id=teabar-cli"
-d "grant_type=urn:ietf:params:oauth:grant-type:device_code"
-d "device_code=ABC123..." Refreshing Tokens
Access tokens are short-lived. Use refresh tokens to obtain new access tokens:
curl -X POST "https://auth.bcp.technology/realms/teabar/protocol/openid-connect/token"
-d "grant_type=refresh_token"
-d "refresh_token=$REFRESH_TOKEN"
-d "client_id=teabar-cli" Tip
Role-Based Access
Permissions are controlled via Keycloak roles mapped to Teabar permissions:
| Keycloak Role | Teabar Permission |
|---|---|
teabar-admin | Full access |
teabar-env-manager | Create, manage, delete environments |
teabar-blueprint-manager | Manage blueprints |
teabar-viewer | Read-only access |
Roles are assigned to users and service accounts in Keycloak.
Token Validation
Teabar validates tokens against Keycloak’s JWKS endpoint. Validate a token programmatically:
curl -H "Authorization: Bearer $TOKEN"
https://api.teabar.dev/teabar.v1.AuthService/GetCurrentUser Response:
{
"user": {
"id": "user_abc123",
"email": "[email protected]",
"name": "John Doe"
},
"organization": {
"id": "org_xyz789",
"slug": "my-company"
}
} Best Practices
Token Security
- Never expose tokens in code - Use environment variables
- Use secrets management - HashiCorp Vault, AWS Secrets Manager
- Limit service account roles - Request minimum required permissions
- Enable MFA in Keycloak - For interactive users
Token Storage
| Environment | Recommended Storage |
|---|---|
| CI/CD | Pipeline secrets/variables |
| Server | Secrets manager or env vars |
| Desktop | OS keychain (teactl default) |
| Web App | httpOnly cookies (server-side) |
Service Account Best Practices
- Create dedicated service accounts per use case
- Rotate client secrets periodically
- Assign minimal roles needed
- Audit usage via Keycloak logs
Error Responses
Invalid Token
{
"code": "unauthenticated",
"message": "Invalid or expired token"
} HTTP Status: 401 Unauthorized
Insufficient Permissions
{
"code": "permission_denied",
"message": "User does not have required role"
} HTTP Status: 403 Forbidden
Token Expired
{
"code": "unauthenticated",
"message": "Token has expired"
} Solution: Refresh the token or re-authenticate.
Code Examples
TypeScript
import { createClient } from "@connectrpc/connect";
import { createConnectTransport } from "@connectrpc/connect-web";
import { EnvironmentService } from "./gen/teabar/v1/environment_connect";
const transport = createConnectTransport({
baseUrl: "https://api.teabar.dev",
interceptors: [
(next) => async (req) => {
req.header.set("Authorization", `Bearer ${process.env.TEABAR_TOKEN}`);
return next(req);
},
],
});
const client = createClient(EnvironmentService, transport); Go
import (
"context"
"google.golang.org/grpc"
"google.golang.org/grpc/metadata"
)
// Add token to context
ctx := metadata.AppendToOutgoingContext(
context.Background(),
"authorization", "Bearer "+token,
)
// Make request with authenticated context
resp, err := client.ListEnvironments(ctx, &ListEnvironmentsRequest{}) Python
import grpc
# Create authenticated channel
credentials = grpc.access_token_call_credentials(token)
channel = grpc.secure_channel(
'api.teabar.dev:443',
grpc.composite_channel_credentials(
grpc.ssl_channel_credentials(),
credentials
)
) Self-Hosted Configuration
For self-hosted deployments with your own OIDC provider:
# Helm values.yaml
auth:
oidc:
issuerURL: "https://your-idp.example.com/realms/teabar"
webClientID: "teabar-web"
webClientSecret: "${OIDC_CLIENT_SECRET}"
cliClientID: "teabar-cli"
audience: "teabar-web" See Also
- CI/CD Authentication - Service account setup
- CLI Authentication - CLI auth methods
- Configuration - Full auth setup