Configuring the VCF SSO Authentication Backend Module#
This guide covers all configuration options for the VCF SSO authentication backend module.
Configuration Structure#
auth:
environment: development # or production
providers:
vcfsso:
development:
clientId: ${VCFSSO_CLIENT_ID}
clientSecret: ${VCFSSO_CLIENT_SECRET}
metadataUrl: https://vcf-sso.example.com/oidc/endpoint/VCFSSO
callbackUrl: http://localhost:7007/api/auth/vcfsso/handler/frame # optional
additionalScopes: [] # optional
prompt: login # optional
signIn:
resolvers:
- resolver: emailLocalPartMatchingUserEntityName
- resolver: emailMatchingUserEntityProfileEmail
production:
clientId: ${VCFSSO_CLIENT_ID}
clientSecret: ${VCFSSO_CLIENT_SECRET}
metadataUrl: https://vcf-sso.example.com/oidc/endpoint/VCFSSO
callbackUrl: https://backstage.example.com/api/auth/vcfsso/handler/frame
signIn:
resolvers:
- resolver: emailMatchingUserEntityProfileEmail
Configuration Parameters#
Required Parameters#
| Parameter | Type | Description |
|---|---|---|
clientId |
string | OIDC client ID from VCF SSO |
clientSecret |
string | OIDC client secret from VCF SSO |
metadataUrl |
string | OIDC discovery endpoint URL (everything before .well-known/openid-configuration) |
Optional Parameters#
| Parameter | Type | Default | Description |
|---|---|---|---|
callbackUrl |
string | Auto-derived | OAuth2 callback URL. Backstage derives this automatically; set only if you need to override it. |
additionalScopes |
string or string[] | [] |
Extra OAuth2 scopes to request beyond openid profile email |
prompt |
string | — | OIDC prompt parameter: login, none, consent, or select_account |
Sign-In Resolvers#
Sign-in resolvers map authenticated VCF SSO users to Backstage user entities.
emailLocalPartMatchingUserEntityName#
Matches the local part of the user's email (before @) to a Backstage user entity by metadata.name:
signIn:
resolvers:
- resolver: emailLocalPartMatchingUserEntityName
Example: User with acct = john.doe@example.com → matches Backstage user entity named john.doe
Optional parameters:
- resolver: emailLocalPartMatchingUserEntityName
allowedDomains:
- example.com # Only allow sign-in from these domains
dangerouslyAllowSignInWithoutUserInCatalog: false # Default: false
emailMatchingUserEntityProfileEmail#
Matches the full email address to a Backstage user entity's spec.profile.email:
signIn:
resolvers:
- resolver: emailMatchingUserEntityProfileEmail
Example: User with acct = john.doe@example.com → matches Backstage user entity with spec.profile.email: john.doe@example.com
Optional parameters:
- resolver: emailMatchingUserEntityProfileEmail
dangerouslyAllowSignInWithoutUserInCatalog: false # Default: false
preferredUsernameMatchingUserEntityName#
Matches the user_name OIDC claim to a Backstage user entity by metadata.name:
signIn:
resolvers:
- resolver: preferredUsernameMatchingUserEntityName
Example: User with user_name = johndoe → matches Backstage user entity named johndoe
Optional parameters:
- resolver: preferredUsernameMatchingUserEntityName
dangerouslyAllowSignInWithoutUserInCatalog: false # Default: false
Multiple Resolvers#
Configure multiple resolvers for fallback logic — Backstage tries each in order until one succeeds:
signIn:
resolvers:
- resolver: emailMatchingUserEntityProfileEmail
- resolver: emailLocalPartMatchingUserEntityName
- resolver: preferredUsernameMatchingUserEntityName
Environment Variables#
Setting Variables#
Development (local shell):
export VCFSSO_CLIENT_ID="your-client-id"
export VCFSSO_CLIENT_SECRET="your-client-secret"
Production (Kubernetes Secret):
apiVersion: v1
kind: Secret
metadata:
name: backstage-secrets
type: Opaque
stringData:
VCFSSO_CLIENT_ID: "your-client-id"
VCFSSO_CLIENT_SECRET: "your-client-secret"
VCF SSO Claim Handling#
VCF SSO uses non-standard OIDC claims. The module handles this automatically:
| Standard Claim | VCF SSO Equivalent | Notes |
|---|---|---|
email |
acct |
VCF SSO does not populate the standard email claim |
preferred_username |
user_name |
Short username |
name |
name |
Standard display name (may be present) |
The module resolves the profile in this priority order:
- Email: acct → fallback to standard email
- Display name: name → fallback to acct → fallback to user_name
Configuration Examples#
Basic Development Setup#
auth:
environment: development
providers:
vcfsso:
development:
clientId: ${VCFSSO_CLIENT_ID}
clientSecret: ${VCFSSO_CLIENT_SECRET}
metadataUrl: https://vcf-sso.lab.example.com/oidc/endpoint/VCFSSO
signIn:
resolvers:
- resolver: emailLocalPartMatchingUserEntityName
Production Setup#
auth:
environment: production
providers:
vcfsso:
production:
clientId: ${VCFSSO_CLIENT_ID}
clientSecret: ${VCFSSO_CLIENT_SECRET}
metadataUrl: https://vcf-sso.example.com/oidc/endpoint/VCFSSO
callbackUrl: https://backstage.example.com/api/auth/vcfsso/handler/frame
signIn:
resolvers:
- resolver: emailMatchingUserEntityProfileEmail
- resolver: emailLocalPartMatchingUserEntityName
Force Re-Authentication (Login Prompt)#
Force users to re-enter credentials on every sign-in:
auth:
providers:
vcfsso:
production:
# ... credentials and metadataUrl ...
prompt: login
signIn:
resolvers:
- resolver: emailMatchingUserEntityProfileEmail
Allow Sign-In Without Catalog Entry (Development Only)#
For development environments where catalog entries may not exist:
auth:
providers:
vcfsso:
development:
# ... credentials and metadataUrl ...
signIn:
resolvers:
- resolver: emailLocalPartMatchingUserEntityName
dangerouslyAllowSignInWithoutUserInCatalog: true
!!! warning
Never use dangerouslyAllowSignInWithoutUserInCatalog: true in production. It bypasses catalog-based access control.
Domain-Restricted Sign-In#
Only allow users from specific email domains:
auth:
providers:
vcfsso:
production:
# ... credentials and metadataUrl ...
signIn:
resolvers:
- resolver: emailLocalPartMatchingUserEntityName
allowedDomains:
- example.com
- corp.example.com
Multi-Environment (Dev + Prod)#
auth:
providers:
vcfsso:
development:
clientId: ${VCFSSO_DEV_CLIENT_ID}
clientSecret: ${VCFSSO_DEV_CLIENT_SECRET}
metadataUrl: https://vcf-sso-dev.example.com/oidc/endpoint/VCFSSO
signIn:
resolvers:
- resolver: emailLocalPartMatchingUserEntityName
dangerouslyAllowSignInWithoutUserInCatalog: true
production:
clientId: ${VCFSSO_PROD_CLIENT_ID}
clientSecret: ${VCFSSO_PROD_CLIENT_SECRET}
metadataUrl: https://vcf-sso.example.com/oidc/endpoint/VCFSSO
signIn:
resolvers:
- resolver: emailMatchingUserEntityProfileEmail
Security Considerations#
- Never commit secrets to version control — always use environment variables
- Use HTTPS for all OAuth2 flows in production
- Restrict allowed domains to prevent unauthorized sign-in via
allowedDomains - Provision user entities in the catalog before first login when not using
dangerouslyAllowSignInWithoutUserInCatalog - Rotate client secrets periodically and update environment variables accordingly
Troubleshooting#
OIDC Discovery Fails at Startup#
- Verify the
metadataUrlreturns valid JSON - Check network connectivity from the Backstage backend to the VCF SSO host
- Validate the TLS certificate of the VCF SSO endpoint
User Not Resolved#
- Check backend logs for the specific resolver error
- Verify the user entity exists in the catalog with matching email or name
- Ensure
spec.profile.emailis set on the user entity (foremailMatchingUserEntityProfileEmail) - Try adding
dangerouslyAllowSignInWithoutUserInCatalog: truetemporarily to confirm the auth flow itself works
Token Exchange Fails#
- Verify
clientIdandclientSecretare correct and match the VCF SSO application - Ensure the callback URL is registered in VCF SSO exactly as configured
- Check that the VCF SSO application is active and not expired