APIPortalAuth
Configure API Portal authentication with the APIPortalAuth Resource.
Introduction
The APIPortalAuth resource provides a declarative way to configure authentication for your API Portal in Traefik Hub API Management. This resource works in both online and offline environments, allowing you to manage portal
authentication settings through Kubernetes manifests.
APIPortalAuth enables per-namespace portal authentication overrides, allowing you to run different portal authentication methods on the same gateway by placing portals in different namespaces.
Now your workspace settings act as a "global default" that you can override on a per-namespace basis with CRDs.
When defined, the CRD configuration takes precedence over workspace-level dashboard settings, providing Infrastructure as Code capabilities for API Portal authentication configuration and is essential for offline environments where connectivity to the Traefik Hub Online Dashboard is restricted or unavailable.
Example Use Case: You can now have a customer-facing portal in the public namespace using Auth0 authentication, an internal developer portal in the internal namespace using Azure AD authentication, and a partner portal
in the partners namespace using Keycloak authentication - all on the same gateway!
APIPortalAuth supports two authentication methods:
OpenID Connect (OIDC) Authentication
- Configurable JWT claim mappings to user attributes
- Flexible attribute synchronization from the OIDC provider (online mode only)
- Support for popular identity providers like Auth0, Azure AD, and Keycloak
LDAP Authentication
- Direct authentication against LDAP servers (OpenLDAP, Active Directory, etc.)
- Static group retrieval via
memberOfattribute - Configurable LDAP attribute mappings to user attributes
- Flexible attribute synchronization from LDAP (online mode only)
- Cookie-based session management for portal users
How APIPortalAuth Works
APIPortalAuth authenticates users accessing your API Portal using either OpenID Connect (OIDC) or LDAP. Each APIPortalAuth resource is namespace-scoped and must be
explicitly referenced by an APIPortal resource in the same namespace.
The authentication method you choose determines how users log into the portal:
- OIDC: Users are redirected to an external identity provider for authentication, then redirected back to the portal
- LDAP: Users enter their LDAP credentials directly on the portal login page, which are validated against the LDAP server
Configuration Example
Configure APIPortalAuth with either OIDC or LDAP authentication.
- OIDC
- LDAP
OIDC authentication provides secure user authentication using OpenID Connect protocol.
apiVersion: hub.traefik.io/v1alpha1
kind: APIPortalAuth
metadata:
name: oidc-auth
namespace: apps
spec:
oidc:
issuerUrl: https://auth.example.com
secretName: oidc-credentials
claims:
groups: groups
userId: sub
email: email
firstname: given_name
lastname: family_name
scopes:
- openid
- profile
- email
- groups
LDAP authentication validates user credentials directly against an LDAP server.
apiVersion: hub.traefik.io/v1alpha1
kind: APIPortalAuth
metadata:
name: ldap-auth
namespace: apps
spec:
ldap:
url: ldaps://ldap.example.com:636
baseDN: dc=example,dc=org
bindDN: cn=admin,dc=example,dc=org
bindPasswordSecretName: ldap-bind-secret
searchFilter: (&(objectClass=inetOrgPerson)(uid=%s))
groups:
memberOfAttribute: memberOf
attributes:
userId: uid
email: mail
firstname: givenName
lastname: sn
Configuration Options
Exactly one of oidc or ldap must be specified in the APIPortalAuth configuration.
OIDC Configuration Options
| Field | Description | Required | Default |
|---|---|---|---|
oidc | OIDC configuration object | Yes (if not using LDAP) | - |
oidc.issuerUrl | OIDC provider issuer URL | Yes | - |
oidc.secretName | Name of Kubernetes Secret containing clientId and clientSecret | Yes | - |
oidc.claims | JWT claim mappings for user attributes | Yes | - |
oidc.claims.groups | JWT claim for user groups (required for authorization) | Yes | - |
oidc.claims.userId | JWT claim for user ID mapping | No | - |
oidc.claims.email | JWT claim for user email | No | - |
oidc.claims.firstname | JWT claim for user first name | No | - |
oidc.claims.lastname | JWT claim for user last name | No | - |
oidc.claims.company | JWT claim for user company | No | - |
oidc.scopes | OAuth2 scopes to request | No | - |
oidc.syncedAttributes | JWT claims to extract and sync to the Traefik Hub platform during authentication (online mode only). Each attribute must correspond to a configured claim. Valid values: groups, userId, firstname, lastname, email, company (max 6 items) | No | - |
- The
issuerUrlmust be a valid URL format - The
secretNamemust be 253 characters or less - The
syncedAttributescan contain at most 6 items and must be from the allowed values - Each attribute in
syncedAttributesmust correspond to a configured claim field
LDAP Configuration Options
| Field | Description | Required | Default |
|---|---|---|---|
ldap | LDAP configuration object | Yes (if not using OIDC) | - |
ldap.url | LDAP server URL, including protocol (ldap:// or ldaps://) and port (for example, ldaps://ldap.example.com:636) | Yes | - |
ldap.baseDN | Base domain name for bind and search queries (for example, dc=example,dc=org) | Yes | - |
ldap.bindDN | Domain name to bind for authentication when running in search mode. If empty, anonymous bind is used (not recommended for production) | No | - |
ldap.bindPasswordSecretName | Name of Kubernetes Secret containing the bind password (must be the value of a key named password) | No | - |
ldap.attribute | LDAP object attribute used to form bind DN. Bind DN format: <attribute>=<username>,<baseDN> | No | cn |
ldap.searchFilter | LDAP search filter query. Use %s as placeholder for username (for example, (&(objectClass=inetOrgPerson)(uid=%s))) | No | - |
ldap.startTLS | Enable StartTLS when initializing connection with LDAP server | No | false |
ldap.insecureSkipVerify | Skip TLS certificate verification (not recommended for production) | No | false |
ldap.certificateAuthority | PEM-encoded certificate for TLS connection with custom Certificate Authority | No | - |
ldap.groups | Group extraction configuration | No | - |
ldap.groups.memberOfAttribute | LDAP attribute containing group memberships (for example, memberOf) | No | memberOf |
ldap.attributes | LDAP attribute mappings for user attributes | No | - |
ldap.attributes.userId | LDAP attribute for user ID mapping | No | - |
ldap.attributes.firstname | LDAP attribute for user first name | No | - |
ldap.attributes.lastname | LDAP attribute for user last name | No | - |
ldap.attributes.email | LDAP attribute for user email | No | - |
ldap.attributes.company | LDAP attribute for user company | No | - |
ldap.syncedAttributes | Array of user attributes to synchronize with Traefik Hub platform (online mode only). Each item must be one of: groups, userId, firstname, lastname, email, company. | No | - |
- The
urlmust be a valid LDAP URL starting withldap://orldaps:// - The
bindPasswordSecretNamemust reference a secret with apasswordkey - The
syncedAttributescan contain at most 6 items and must be from the allowed values - Each attribute in
syncedAttributesmust have a corresponding mapping in theattributessection - Groups are extracted statically from the
memberOfattribute; dynamic group queries are not supported
Secret Configuration
OIDC Client Secret
When using OIDC authentication, create a Kubernetes Secret containing the OIDC client credentials:
- kubectl
- YAML
kubectl create secret generic oidc-client-secret \
--from-literal=clientId=your-client-id \
--from-literal=clientSecret=your-client-secret \
-n apps
apiVersion: v1
kind: Secret
metadata:
name: oidc-client-secret
namespace: apps
type: Opaque
data:
clientId: <base64-encoded-client-id>
clientSecret: <base64-encoded-client-secret>
LDAP Bind Password Secret
When using LDAP authentication with a bind DN, create a Kubernetes Secret containing the bind password:
- kubectl
- YAML
kubectl create secret generic ldap-bind-secret \
--from-literal=password=your-bind-password \
-n apps
apiVersion: v1
kind: Secret
metadata:
name: ldap-bind-secret
namespace: apps
type: Opaque
data:
password: <base64-encoded-bind-password>
The LDAP bind password secret must contain a key named password.
Advanced Configuration
JWT Claim Mapping
Configure how JWT claims from your OIDC provider map to user attributes:
apiVersion: hub.traefik.io/v1alpha1
kind: APIPortalAuth
metadata:
name: custom-claims
namespace: apps
spec:
oidc:
issuerUrl: https://auth.example.com
secretName: oidc-credentials
claims:
groups: https://example.com/groups # Custom groups claim
userId: user_id # Custom user ID claim
email: user_email # Custom email claim
company: organization # Custom company claim
firstname: first_name # Custom first name claim
lastname: last_name # Custom last name claim
OAuth2 Scopes
Configure the OAuth2 scopes requested during authentication:
apiVersion: hub.traefik.io/v1alpha1
kind: APIPortalAuth
metadata:
name: scoped-auth
namespace: apps
spec:
oidc:
issuerUrl: https://auth.example.com
secretName: oidc-credentials
scopes:
- openid # Always required for OIDC
- profile # For basic profile information
- email # For email claim
- groups # For groups claim
claims:
groups: groups
email: email
LDAP Attribute Mapping
Configure how LDAP attributes map to user attributes in Traefik Hub:
apiVersion: hub.traefik.io/v1alpha1
kind: APIPortalAuth
metadata:
name: ldap-custom-attributes
namespace: apps
spec:
ldap:
url: ldaps://ldap.example.com:636
baseDN: dc=example,dc=org
bindDN: cn=admin,dc=example,dc=org
bindPasswordSecretName: ldap-bind-secret
searchFilter: (&(objectClass=inetOrgPerson)(uid=%s))
attributes:
userId: uid # Map LDAP 'uid' to user ID
email: mail # Map LDAP 'mail' to email
firstname: givenName # Map LDAP 'givenName' to first name
lastname: sn # Map LDAP 'sn' to last name
company: o # Map LDAP 'o' (organization) to company
LDAP TLS Configuration
Configure secure TLS connections to your LDAP server:
- LDAPS
- StartTLS
- Custom CA
apiVersion: hub.traefik.io/v1alpha1
kind: APIPortalAuth
metadata:
name: ldap-tls
namespace: apps
spec:
ldap:
url: ldaps://ldap.example.com:636 # Use ldaps:// for TLS
baseDN: dc=example,dc=org
bindDN: cn=admin,dc=example,dc=org
bindPasswordSecretName: ldap-bind-secret
apiVersion: hub.traefik.io/v1alpha1
kind: APIPortalAuth
metadata:
name: ldap-starttls
namespace: apps
spec:
ldap:
url: ldap://ldap.example.com:389 # Use ldap:// with StartTLS
startTLS: true # Enable StartTLS
baseDN: dc=example,dc=org
bindDN: cn=admin,dc=example,dc=org
bindPasswordSecretName: ldap-bind-secret
apiVersion: hub.traefik.io/v1alpha1
kind: APIPortalAuth
metadata:
name: ldap-custom-ca
namespace: apps
spec:
ldap:
url: ldaps://ldap.example.com:636
certificateAuthority: |
-----BEGIN CERTIFICATE-----
MIIDXTCCAkWgAwIBAgIJAKJ... (your CA certificate)
-----END CERTIFICATE-----
baseDN: dc=example,dc=org
bindDN: cn=admin,dc=example,dc=org
bindPasswordSecretName: ldap-bind-secret
LDAP Group Configuration
Configure how groups are extracted from LDAP:
apiVersion: hub.traefik.io/v1alpha1
kind: APIPortalAuth
metadata:
name: ldap-groups
namespace: apps
spec:
ldap:
url: ldaps://ldap.example.com:636
baseDN: dc=example,dc=org
bindDN: cn=admin,dc=example,dc=org
bindPasswordSecretName: ldap-bind-secret
searchFilter: (&(objectClass=inetOrgPerson)(uid=%s))
groups:
memberOfAttribute: memberOf # LDAP attribute containing group DNs
Groups are extracted statically from the memberOf attribute (or the attribute you specify). Each value in this attribute is expected to be a group DN
(for example, cn=developers,ou=groups,dc=example,dc=org). The group name (CN part) is extracted and used for portal access control.
Attribute Synchronization
Attribute synchronization configures which attributes should be extracted and stored by the Traefik Hub platform during authentication. These stored attributes are used for user management and portal functionality.
- Attribute synchronization requires online connectivity to the Traefik Hub platform. In offline mode, attributes are processed locally for authentication but are not synchronized to the platform.
- OIDC: You can only synchronize attributes that you've also configured in the
claimssection. Each item insyncedAttributesmust correspond to a claim field you've defined. - LDAP: You can only synchronize attributes that you've also configured in the
attributessection. Each item insyncedAttributesmust correspond to an attribute mapping you've defined.
apiVersion: hub.traefik.io/v1alpha1
kind: APIPortalAuth
metadata:
name: synced-auth
namespace: apps
spec:
oidc:
issuerUrl: https://auth.example.com
secretName: oidc-credentials
claims:
groups: groups
userId: sub
email: email
firstname: given_name
lastname: family_name
syncedAttributes:
- groups # Synchronize group memberships
- email # Synchronize email addresses
- firstname # Synchronize first names
- lastname # Synchronize last names
In this example:
- The
claimssection maps JWT claims (groups,sub,email, etc.) to user attributes - The
syncedAttributessection specifies which of those mapped attributes should be sent to the Traefik Hub platform (online mode only) - When users authenticate in online mode, Traefik Hub will extract the
groups,email,given_name, andfamily_namevalues from their JWT tokens and store them
OIDC Provider Integration
Configure APIPortalAuth for popular OIDC providers:
- Auth0
- Azure AD
- Keycloak
- Okta
- Oracle OCI Identity
apiVersion: hub.traefik.io/v1alpha1
kind: APIPortalAuth
metadata:
name: auth0-integration
namespace: apps
spec:
oidc:
issuerUrl: https://your-domain.auth0.com/
secretName: auth0-credentials
scopes:
- openid
- profile
- email
claims:
groups: https://your-domain.com/groups
userId: sub
email: email
firstname: given_name
lastname: family_name
---
apiVersion: v1
kind: Secret
metadata:
name: portal-oidc-secret
namespace: apps
type: Opaque
data:
clientId: <base64-encoded-client-id>
clientSecret: <base64-encoded-client-secret>
apiVersion: hub.traefik.io/v1alpha1
kind: APIPortalAuth
metadata:
name: azure-ad-integration
namespace: apps
spec:
oidc:
issuerUrl: https://login.microsoftonline.com/your-tenant-id/v2.0
secretName: azure-ad-credentials
scopes:
- openid
- profile
- email
claims:
groups: groups
userId: oid
email: email
firstname: given_name
lastname: family_name
syncedAttributes:
- groups
- email
- firstname
- lastname
---
apiVersion: v1
kind: Secret
metadata:
name: azure-ad-credentials
namespace: apps
type: Opaque
data:
clientId: your-azure-app-id
clientSecret: your-azure-app-secret
apiVersion: hub.traefik.io/v1alpha1
kind: APIPortalAuth
metadata:
name: keycloak-integration
namespace: apps
spec:
oidc:
issuerUrl: https://your-keycloak-domain.com/realms/your-realm
secretName: keycloak-credentials
scopes:
- openid
- profile
- email
claims:
groups: groups
userId: sub
email: email
firstname: given_name
lastname: family_name
syncedAttributes:
- email
---
apiVersion: v1
kind: Secret
metadata:
name: keycloak-credentials
namespace: apps
type: Opaque
data:
clientId: your-keycloak-client-id
clientSecret: your-keycloak-client-secret
apiVersion: hub.traefik.io/v1alpha1
kind: APIPortalAuth
metadata:
name: okta-integration
namespace: apps
spec:
oidc:
issuerUrl: https://your-domain.okta.com # Tweak this to your custom auth server URL (if needed)
secretName: okta-credentials
scopes:
- openid
- profile
- email
- groups
claims:
groups: groups
userId: sub
email: email
firstname: given_name
lastname: family_name
syncedAttributes:
- groups
- email
- firstname
- lastname
---
apiVersion: v1
kind: Secret
metadata:
name: okta-credentials
namespace: apps
type: Opaque
data:
clientId: <base64-encoded-client-id>
clientSecret: <base64-encoded-client-secret>
apiVersion: hub.traefik.io/v1alpha1
kind: APIPortalAuth
metadata:
name: oci-integration
namespace: apps
spec:
oidc:
issuerUrl: https://your-domain.identity.oraclecloud.com
secretName: oci-credentials
scopes:
- openid
- profile
- email
claims:
groups: groups
userId: sub
email: email
firstname: given_name
lastname: family_name
syncedAttributes:
- groups
- email
- firstname
- lastname
---
apiVersion: v1
kind: Secret
metadata:
name: oci-credentials
namespace: apps
type: Opaque
data:
clientId: <base64-encoded-client-id>
clientSecret: <base64-encoded-client-secret>
LDAP Provider Integration
Configure APIPortalAuth for popular LDAP servers:
- OpenLDAP
- Active Directory
- Oracle Internet Directory
apiVersion: hub.traefik.io/v1alpha1
kind: APIPortalAuth
metadata:
name: openldap-auth
namespace: apps
spec:
ldap:
url: ldaps://openldap.example.com:636
baseDN: dc=example,dc=org
bindDN: cn=admin,dc=example,dc=org
bindPasswordSecretName: openldap-bind-secret
searchFilter: (&(objectClass=inetOrgPerson)(uid=%s))
groups:
memberOfAttribute: memberOf
attributes:
userId: uid
email: mail
firstname: givenName
lastname: sn
syncedAttributes:
- groups
- email
---
apiVersion: v1
kind: Secret
metadata:
name: openldap-bind-secret
namespace: apps
type: Opaque
stringData:
password: admin-password
apiVersion: hub.traefik.io/v1alpha1
kind: APIPortalAuth
metadata:
name: ad-auth
namespace: apps
spec:
ldap:
url: ldaps://ad.example.com:636
baseDN: dc=example,dc=com
bindDN: cn=Service Account,ou=Service Accounts,dc=example,dc=com
bindPasswordSecretName: ad-bind-secret
searchFilter: (&(objectClass=user)(sAMAccountName=%s))
groups:
memberOfAttribute: memberOf
attributes:
userId: sAMAccountName
email: mail
firstname: givenName
lastname: sn
company: company
syncedAttributes:
- groups
- email
- firstname
- lastname
---
apiVersion: v1
kind: Secret
metadata:
name: ad-bind-secret
namespace: apps
type: Opaque
stringData:
password: service-account-password
apiVersion: hub.traefik.io/v1alpha1
kind: APIPortalAuth
metadata:
name: oid-auth
namespace: apps
spec:
ldap:
url: ldaps://oid.example.com:636
baseDN: dc=example,dc=com
bindDN: cn=orcladmin
bindPasswordSecretName: oid-bind-secret
searchFilter: (&(objectClass=person)(uid=%s))
groups:
memberOfAttribute: memberOf
attributes:
userId: uid
email: mail
firstname: givenName
lastname: sn
syncedAttributes:
- groups
- email
---
apiVersion: v1
kind: Secret
metadata:
name: oid-bind-secret
namespace: apps
type: Opaque
stringData:
password: orcladmin-password
Integration with API Portal
- OIDC Example
- LDAP Example
APIPortalAuth with OIDC:
apiVersion: hub.traefik.io/v1alpha1
kind: APIPortalAuth
metadata:
name: portal-auth-config
namespace: apps
spec:
oidc:
issuerUrl: https://auth.company.com
secretName: portal-oidc-secret
scopes:
- openid
- profile
- email
- groups
claims:
groups: groups
userId: sub
email: email
firstname: given_name
lastname: family_name
company: organization
syncedAttributes:
- groups
- email
- firstname
- lastname
---
apiVersion: v1
kind: Secret
metadata:
name: portal-oidc-secret
namespace: apps
type: Opaque
data:
clientId: portal-client-id
clientSecret: portal-client-secret
---
apiVersion: hub.traefik.io/v1alpha1
kind: APIPortal
metadata:
name: company-portal
namespace: apps
spec:
title: Company API Portal
description: "Official API documentation portal"
trustedUrls:
- https://portal.company.com
auth:
name: portal-auth-config # References APIPortalAuth resource
APIPortalAuth with LDAP:
apiVersion: hub.traefik.io/v1alpha1
kind: APIPortalAuth
metadata:
name: portal-ldap-auth
namespace: apps
spec:
ldap:
url: ldaps://ldap.company.com:636
baseDN: dc=company,dc=com
bindDN: cn=service,dc=company,dc=com
bindPasswordSecretName: ldap-secret
searchFilter: (&(objectClass=inetOrgPerson)(uid=%s))
groups:
memberOfAttribute: memberOf
attributes:
userId: uid
email: mail
firstname: givenName
lastname: sn
syncedAttributes:
- groups
- email
---
apiVersion: v1
kind: Secret
metadata:
name: ldap-secret
namespace: apps
type: Opaque
stringData:
password: service-password
---
apiVersion: hub.traefik.io/v1alpha1
kind: APIPortal
metadata:
name: company-portal
namespace: apps
spec:
title: Company API Portal
description: "Official API documentation portal"
trustedUrls:
- https://portal.company.com
auth:
name: portal-ldap-auth # References APIPortalAuth resource

Configuration via Dashboard UI
You can also configure LDAP portal authentication through the Traefik Hub Dashboard UI in addition to using CRDs.
- UI Configuration: Convenient for quick setup and testing, configuration stored in Traefik Hub platform. The UI setting is global for the entire workspace and applies to all API Portals across all clusters and namespaces.
- CRD Configuration: Infrastructure as Code approach, version controlled, essential for offline environments. APIPortalAuth CRDs are namespace-scoped, allowing different portal authentication methods per cluster or per namespace within the same workspace.
- Precedence: CRD configuration takes precedence over UI configuration when both are defined
This namespace-scoped approach enables advanced scenarios like having an Auth0-authenticated portal in the public namespace,
an Azure AD-authenticated portal in the internal namespace, and an LDAP-authenticated portal in the partners namespace - all within the same workspace on the same gateway.
Validation
Use the Traefik Hub static analyzer to validate your APIPortalAuth configuration:
hub-static-analyzer lint --path [path/to/manifests] --offline
The analyzer will ensure all APIPortal resources have an APIPortalAuth attached.
Migration from Traefik Hub Online Dashboard Configuration
Migrating OIDC Configuration
When migrating from online dashboard portal authentication to APIPortalAuth CRDs:
- Export Current Settings: Note your OIDC configuration from the online dashboard
- Create APIPortalAuth Resource: Convert dashboard settings to APIPortalAuth CRD format
- Create Client Secret: Store OIDC client credentials in Kubernetes Secret
- Update APIPortal: Reference the APIPortalAuth resource in your APIPortal
- Test Authentication: Verify portal authentication works correctly
OIDC Migration Example
Traefik Hub Online Dashboard OIDC configuration:
- Issuer:
https://auth.company.com - Client ID:
portal-client - Groups claim:
groups - Email claim:
email
Equivalent APIPortalAuth CRD:
apiVersion: hub.traefik.io/v1alpha1
kind: APIPortalAuth
metadata:
name: migrated-auth
namespace: apps
spec:
oidc:
issuerUrl: https://auth.company.com
secretName: migrated-oidc-secret
claims:
groups: groups
email: email
---
apiVersion: v1
kind: Secret
metadata:
name: migrated-oidc-secret
namespace: apps
type: Opaque
data:
clientId: portal-client
clientSecret: your-client-secret
Migrating LDAP Configuration
When migrating LDAP portal authentication from the dashboard to CRDs:
- Export Current Settings: Note your LDAP configuration from the online dashboard
- Create APIPortalAuth Resource: Convert dashboard settings to APIPortalAuth CRD format
- Create Bind Secret: Store LDAP bind password in Kubernetes Secret
- Update APIPortal: Reference the APIPortalAuth resource in your APIPortal
- Test Authentication: Verify portal login works correctly with LDAP credentials
Related Content
- Learn more about LDAP authentication overview for a comprehensive guide
- Learn more about the APIAuth in its dedicated section
- Learn more about the APIPortal in its dedicated section
- Learn more about Users and Groups in its dedicated section