{
  "id": "configure-auth",
  "title": "Configure authentication and RBAC",
  "url": "https://redis.io/docs/latest/operate/featureform/configure-auth/",
  "summary": "Configure deployment-wide authentication and RBAC for Redis Feature Form.",
  "tags": [
    "docs",
    "operate",
    "featureform"
  ],
  "last_updated": "2026-07-30T11:11:54+01:00",
  "page_type": "content",
  "content_hash": "747d768ce22ee2d8b379e272d59b22596a5d6b29c861599c7db8e38dc5f76ca5",
  "sections": [
    {
      "id": "overview",
      "title": "Overview",
      "role": "overview",
      "text": "Redis Feature Form authenticates users and services through an external OIDC identity provider, then enforces built-in role-based access control (RBAC) on their actions. Authentication is a deployment-wide concern configured at install time; authorization is per-workspace (with a small number of deployment-scoped exceptions) and managed at runtime through role bindings.\n\nOpenID Connect (OIDC) is a standard identity layer that lets Feature Form delegate authentication to a separate identity provider (IdP). You operate an IdP yourself (such as Keycloak) or use a managed service (such as Okta); Feature Form reads the resulting JSON Web Tokens (JWTs) to enforce its own role checks.\n\nA [workspace](https://redis.io/docs/latest/develop/ai/featureform/concepts#workspaces) isolates resources; RBAC bindings control who can act on it.\n\nThe sequence:\n\n1. [Configure OIDC at deploy time](#configure-oidc-at-deploy-time)\n2. [Sign in with the CLI](#sign-in-with-the-cli)\n3. [Pick built-in roles for users and groups](#built-in-roles)\n4. [Provision the first global admin](#provision-the-first-global-admin)\n5. [Set up service accounts for non-human identities](#service-accounts-and-machine-credentials)\n6. [Read the audit log](#audit)"
    },
    {
      "id": "authentication",
      "title": "Authentication",
      "role": "security",
      "text": ""
    },
    {
      "id": "configure-oidc-at-deploy-time",
      "title": "Configure OIDC at deploy time",
      "role": "configuration",
      "text": "Set Feature Form's OIDC parameters in the Helm chart's `auth` block. At minimum, you need an issuer URL and a server-side client ID:\n\n[code example]\n\nFor deployments where internal services reach the IdP at a different URL than external clients, use `oidcDiscoveryURL`, `oidcPublicIssuerURL`, and `oidcPublicDiscoveryURL` to split the discovery and issuer endpoints. The `oidcSkipIssuerCheck: true` flag disables issuer-claim validation. Use it only during local development.\n\nFeature Form reads role information from JWT claims on each request. It checks the following claims, in order, for matches against built-in role IDs:\n\n- `featureform_roles` (string or array)\n- `roles` (string or array)\n- `role` (string)\n- `realm_access.roles` (array; Keycloak convention)\n\nIf any of those claims contain `global_admin`, Feature Form treats the user as a global admin for that token's lifetime without a database binding. This is the typical way operators bootstrap the first admin — see [Provision the first global admin](#provision-the-first-global-admin)."
    },
    {
      "id": "sign-in-with-the-cli",
      "title": "Sign in with the CLI",
      "role": "content",
      "text": "The `ff auth` commands handle login, session inspection, and token retrieval:\n\n[code example]\n\nPick a login method based on your environment:\n\n- **device-code** for headless terminals or shared shells where a local browser callback can't be reached.\n- **authorization_code_pkce** when a local browser callback works (typical for developer desktops).\n- **password-stdin** for non-interactive automation like CI scripts.\n\nCLI sessions are stored in the CLI's local config (per profile). To skip interactive login entirely, set `FEATUREFORM_TOKEN` to a valid access token, or configure a service account with client credentials (see [Service accounts and machine credentials](#service-accounts-and-machine-credentials))."
    },
    {
      "id": "rbac",
      "title": "RBAC",
      "role": "content",
      "text": ""
    },
    {
      "id": "built-in-roles",
      "title": "Built-in roles",
      "role": "content",
      "text": "Feature Form has five built-in RBAC roles. The role ID in the left column is the literal string used in `ff rbac grant`.\n\nEach built-in role is a fixed set of finer-grained permissions—the underlying checks the authorization service runs on each request. For the full permission catalog, see [Reference > Permissions](https://redis.io/docs/latest/develop/ai/featureform/reference#permissions).\n\n| Role ID | Scope | What it grants |\n| --- | --- | --- |\n| `viewer` | Workspace | Read-only access to workspace metadata, the resource graph, the catalog, providers, and serving metadata. |\n| `operator` | Workspace | Everything a viewer has, plus writing providers, planning and applying changes, reading served features, and controlling scheduler workflows. |\n| `workspace_admin` | Workspace | Full administration of a single workspace—membership, audit, updates, deletion—plus everything an operator has. |\n| `global_admin` | Global | Workspace creation, plus full administration across every workspace in the deployment. |\n| `model` | Resource-constrained | Read access to a specific set of feature views, training sets, and serving data—nothing else. Used for model-team service accounts. |"
    },
    {
      "id": "role-scopes",
      "title": "Role scopes",
      "role": "content",
      "text": "Every role applies at a defined breadth—deployment-wide, a single workspace, or a specific set of resources within a workspace. Feature Form has three scopes, and each role works at exactly one:\n\n- **Global** — Deployment-wide actions, such as creating workspaces. Only `global_admin` operates at this scope.\n- **Workspace** — Actions inside a single workspace: providers, secret providers, apply, graph, catalog, serving metadata, and audit. A binding at this scope applies to one workspace only — grant the role again on each workspace a user needs.\n- **Resource-constrained** — A narrower form of workspace scope that limits a binding to a specific set of resources. Used for the `model` role, which only sees serving and training-set reads for the resources it was bound to.\n\nA binding pairs a role with a scope and a user, group, or service account. For example: \"Alice has `workspace_admin` on workspace `7f2e4d8c-…`\" or \"the `payments-team` group has `global_admin`.\""
    },
    {
      "id": "provision-the-first-global-admin",
      "title": "Provision the first global admin",
      "role": "content",
      "text": "A fresh Feature Form deployment has no role bindings in its database. There is no dedicated Helm value for an initial admin, so plan your IdP claim mapping before installing. To get the first global admin in place, choose one of two paths:\n\n**Map an IdP claim to `global_admin` (recommended for production).** Configure your IdP to issue a `featureform_roles` claim that contains `global_admin` for the appropriate user or group. Feature Form treats those tokens as global admin without a database binding, so the first admin can sign in and start granting roles to others immediately.\n\n**Bind manually after the first login.** A user with no role can still authenticate; they just can't do anything yet. From a host that already has an access token for a privileged account, run:\n\n[code example]\n\nThis option requires that *some* identity already has `global_admin`, which makes it suitable only for redirecting access from a temporary IdP-claim admin to a database-bound one, or for environments where you can run `ff` commands with a bootstrap token issued out-of-band."
    },
    {
      "id": "service-accounts-and-machine-credentials",
      "title": "Service accounts and machine credentials",
      "role": "content",
      "text": "Non-human identities—CI runners, model-serving processes, batch jobs—authenticate with a service account that holds a public key registered with Feature Form. Feature Form supports Ed25519 keys.\n\nThe end-to-end setup:\n\n1. Register a service-account principal in your IdP.\n2. Create a machine credential that registers the principal's public key with Feature Form.\n3. Grant the service account a workspace role.\n4. Use the resulting token in your automation.\n\nCreate a credential for a service account inside a workspace:\n\n[code example]\n\nThe `ff machine-credential` command also has subcommands for `list`, `get`, `rotate`, `revoke`, and `usage` (for audit-style usage records). All of them require the `machine_credential.write` or `machine_credential.read` permission on the target workspace.\n\nGrant the service account a workspace role the same way you would a user — use `--service-account <id>` instead of `--user <id>`:\n\n[code example]"
    },
    {
      "id": "audit",
      "title": "Audit",
      "role": "content",
      "text": "Feature Form records authorization-relevant events in an audit log. List events with:\n\n[code example]\n\nUseful filters:\n\n- `--workspace <id>` — scope to one workspace.\n- `--global` — only deployment-scoped events. Requires `global_admin`.\n- `--principal-id <id>` — events for a specific user, group, or service account.\n- `--event-type <type>` — filter by event name.\n\nCommon event types include:\n\n- `workspace.create`, `workspace.update`, `workspace.delete`\n- `rbac.grant`, `rbac.revoke`\n- `provider.write`, `secret_provider.write`\n- `apply.write`\n- `machine_credential.create`, `machine_credential.rotate`, `machine_credential.revoke`\n\nEach event includes the scope, workspace ID (if applicable), actor ID, event type, and creation timestamp. Reading the log requires the `audit.read` permission; deployment-scope reads additionally require `global_admin`."
    },
    {
      "id": "next-steps",
      "title": "Next steps",
      "role": "content",
      "text": "- [Deploy](https://redis.io/docs/latest/operate/featureform/deploy) — chart acquisition and install with OIDC enabled.\n- [Manage workspaces](https://redis.io/docs/latest/develop/ai/featureform/manage-workspace) — create workspaces, grant roles, and verify bindings.\n- [Register providers](https://redis.io/docs/latest/develop/ai/featureform/register-providers) — connect Postgres, Redis, S3, and other backends after auth is set up.\n- [Concepts](https://redis.io/docs/latest/develop/ai/featureform/concepts) — background on workspaces and the resource graph.\n- [Quickstart](https://redis.io/docs/latest/develop/ai/featureform/quickstart) — end-to-end verification."
    }
  ],
  "examples": [
    {
      "id": "configure-oidc-at-deploy-time-ex0",
      "language": "yaml",
      "code": "auth:\n  enabled: true\n  oidcIssuerURL: \"https://idp.example.com/realms/featureform\"\n  oidcClientID: \"featureform-server\"\n\n  # CLI client. Defaults to \"featureform-cli\".\n  oidcCLIClientID: \"featureform-cli\"\n\n  # Comma-separated list. Restricts which flows the CLI offers.\n  # Supported values: device_code, authorization_code_pkce\n  oidcCLILoginMethods: \"device_code,authorization_code_pkce\"\n\n  # Required only if you use authorization_code_pkce. Must be\n  # registered with the IdP for the CLI client.\n  oidcCLIRedirectURI: \"http://localhost:8080/callback\"",
      "section_id": "configure-oidc-at-deploy-time"
    },
    {
      "id": "sign-in-with-the-cli-ex0",
      "language": "bash",
      "code": "# Interactive login. Defaults to device-code flow if the IdP\n# supports it; falls back to authorization_code_pkce otherwise.\nff auth login\n\n# Force a specific flow.\nff auth login --login-method device_code\nff auth login --login-method authorization_code_pkce\n\n# Non-interactive password grant for continuous-integration scripts.\nff auth login --username alice@example.com --password-stdin\n\n# Inspect the current session.\nff auth status\nff auth whoami\n\n# Print the active access token (for use in tools that don't\n# integrate with the CLI session).\nff auth token\n\n# Clear the local session. Does not revoke tokens on the IdP.\nff auth logout",
      "section_id": "sign-in-with-the-cli"
    },
    {
      "id": "provision-the-first-global-admin-ex0",
      "language": "bash",
      "code": "ff rbac grant global_admin --global --user <user-principal-id>",
      "section_id": "provision-the-first-global-admin"
    },
    {
      "id": "service-accounts-and-machine-credentials-ex0",
      "language": "bash",
      "code": "ff machine-credential create ci-runner-key \\\n  --workspace <workspace-id> \\\n  --service-account <service-account-principal-id> \\\n  --public-key \"<key material>\" \\\n  --algorithm Ed25519",
      "section_id": "service-accounts-and-machine-credentials"
    },
    {
      "id": "service-accounts-and-machine-credentials-ex1",
      "language": "bash",
      "code": "ff rbac grant operator \\\n  --workspace <workspace-id> \\\n  --service-account ci-runner",
      "section_id": "service-accounts-and-machine-credentials"
    },
    {
      "id": "audit-ex0",
      "language": "bash",
      "code": "ff audit list \\\n  --workspace <workspace-id> \\\n  --event-type workspace.delete \\\n  --page-size 50",
      "section_id": "audit"
    }
  ]
}
