Backstage New Frontend System - Code Examples
This directory contains practical, tested code examples extracted from Backstage core and real-world implementations.
Directory Structure
examples/
├── auth-providers/ ⭐ AUTH PROVIDER EXAMPLES (OIDC/PKCE FOCUS)
│ ├── custom-oidc-ref.ts # Creating custom auth API refs
│ ├── custom-oidc-implementation.tsx # Complete OIDC/PKCE implementation
│ ├── oauth2-create-pattern.tsx # How OAuth2.create() works
│ ├── frontend-backend-matching.tsx # Provider ID matching patterns
│ ├── override-github-scopes.tsx # Overriding standard providers
│ └── generic-oauth2-ref.ts # Generic OAuth2 API ref
│
├── app-creation/
│ ├── basic-app.tsx # Minimal app setup
│ ├── feature-discovery.yaml # Automatic plugin discovery
│ ├── with-custom-config.tsx # Custom configuration
│ └── plugin-overrides.yaml # Override plugin info
│
├── extensions/
│ ├── simple-extension.tsx # Basic extension
│ ├── extension-with-inputs.tsx # Parent/child extensions
│ ├── extension-with-config.tsx # Configuration schema
│ ├── page-blueprint.tsx # Using PageBlueprint
│ └── multiple-attachment-points.tsx # Advanced patterns
│
├── utility-apis/
│ ├── creating-api-ref.ts # Define API contract
│ ├── api-implementation.tsx # Implement and register API
│ ├── api-with-deps.tsx # API depending on other APIs
│ ├── consuming-api.tsx # Use API in components
│ └── api-registration-complete.tsx # Complete registration pattern
│
└── plugins/
├── simple-plugin.tsx # Basic plugin with one page
├── plugin-with-api.tsx # Plugin providing utility API
├── plugin-alpha-export.tsx # Proper alpha subpath export
└── plugin-with-routes.tsx # Plugin with multiple routes
Quick Start
Prerequisites
- Node.js 20 LTS
- Yarn
- Backstage v1.42.0+
Using Examples in Your App
Method 1: Copy and Adapt
- Choose an example that matches your use case
- Copy the code to your app (e.g.,
packages/app/src/) - Adjust imports and configuration
- Test in your environment
Method 2: Test in Fresh App
# Create a new Backstage app with new frontend system
npx @backstage/create-app@latest --next
# Navigate to app directory
cd my-backstage-app/packages/app
# Copy example files
cp /path/to/examples/auth-providers/custom-oidc-implementation.tsx src/modules/auth/
# Install dependencies
yarn install
# Start the app
yarn dev
Example Categories
Auth Provider Examples ⭐ CRITICAL
These examples demonstrate custom OIDC/PKCE implementation, answering all auth provider questions from the deep dive requirements.
custom-oidc-ref.ts
Purpose: Create custom auth API reference
Key Concepts:
- Creating API refs with
createApiRef<T>() - Combining multiple interfaces (OAuthApi, OpenIdConnectApi, etc.)
- Alternative approaches (custom, generic, reuse existing)
When to Use:
- You need a custom auth provider
- Standard refs don't fit your use case
- You want full control over API contract
custom-oidc-implementation.tsx
Purpose: Complete OIDC/PKCE implementation from API ref to app installation
Key Concepts:
- API extension with
ApiBlueprint.make() - Using
OAuth2.create()for OAuth2 flow - Frontend module creation
- Custom sign-in page configuration
- Complete file structure and flow
When to Use:
- Implementing OIDC with PKCE (public client)
- Implementing any custom OAuth2/OIDC provider
- Understanding complete frontend auth setup
Critical Files:
- API ref definition (
oidcPkceAuthApiRef.ts) - API extension (
oidcPkceAuth.tsx) - Frontend module (
index.tsx) - Custom sign-in page (
signInPage/index.tsx) - App installation (
App.tsx)
oauth2-create-pattern.tsx
Purpose: Deep dive into how OAuth2.create() works and why it's provider-agnostic
Key Concepts:
- OAuth2 class internal structure
- Provider-agnostic URL construction
- What OAuth2 does vs doesn't do
- Complete authorization flow (15 steps)
- PKCE transparency proof
When to Use:
- Understanding OAuth2.create() internals
- Debugging auth flow issues
- Verifying PKCE transparency
- Answering "why does this work?"
Other Auth Examples
frontend-backend-matching.tsx: Provider ID synchronization patternsoverride-github-scopes.tsx: Customizing standard providersgeneric-oauth2-ref.ts: Reusable OAuth2 API ref
App Creation Examples
basic-app.tsx
Purpose: Minimal app setup with new frontend system
Key Concepts:
createApp()from@backstage/frontend-defaults- Installing features
- Creating app root
feature-discovery.yaml
Purpose: Automatic plugin discovery configuration
Key Concepts:
app.packages: allconfiguration- Include/exclude filters
- Plugin deduplication
Extension Examples
simple-extension.tsx
Purpose: Basic extension structure
Key Concepts:
createExtension()usage- Extension ID, attachment point, output, factory
- Extension data references
extension-with-inputs.tsx
Purpose: Parent/child extension communication
Key Concepts:
createExtensionInput()usage- Extension data flow
- Optional vs required inputs
extension-with-config.tsx
Purpose: Extension configuration with Zod schema
Key Concepts:
- Configuration schema with Zod
- Default values
- Configuration validation
Utility API Examples
creating-api-ref.ts
Purpose: Define API contract (TypeScript interface + API ref)
Key Concepts:
createApiRef<T>()usage- API ref ID conventions
- Splitting into
-reactpackage for sharing
api-implementation.tsx
Purpose: Implement and register API using ApiBlueprint
Key Concepts:
ApiBlueprint.make()usage- API dependencies
- Factory function patterns
Testing Examples
Local Testing
Method 1: Test in Existing App
-
Backup your app (create a git branch)
git checkout -b test-new-frontend-examples -
Copy example files to appropriate locations:
# Example: Test custom OIDC
mkdir -p packages/app/src/apis
mkdir -p packages/app/src/modules/auth
mkdir -p packages/app/src/modules/signInPage
# Copy API ref
cp examples/auth-providers/custom-oidc-ref.ts packages/app/src/apis/
# Copy API implementation (extract relevant parts)
# Edit and adapt to your needs -
Install dependencies (if needed)
yarn workspace app install -
Configure backend (
app-config.yaml)auth:
providers:
oidc-pkce:
development:
metadataUrl: https://your-idp/.well-known/openid-configuration
clientId: your-client-id -
Start and test
# Terminal 1: Backend
yarn start-backend
# Terminal 2: Frontend
yarn start
# Open http://localhost:3000 -
Verify
- Sign-in page shows custom provider button
- Clicking button opens OAuth popup
- Auth flow completes successfully
- App receives tokens
Method 2: Test in Fresh App
-
Create new app
npx @backstage/create-app@latest --next my-test-app
cd my-test-app -
Apply examples (copy files, edit as needed)
-
Test isolated feature
- Minimal app-config
- Only necessary plugins
- Clean environment
Automated Testing (Future)
We're working on providing a Docker-based testing environment:
# Build test image with Backstage v1.42.0+ (COMING SOON)
docker build -t backstage-test -f Dockerfile.test .
# Run with examples mounted
docker run -it -v $(pwd)/examples:/app/examples backstage-test
# Inside container
cd /app && yarn dev
Common Patterns
Pattern 1: Creating Custom Auth Provider
Files Needed:
- API ref:
src/apis/myAuthApiRef.ts - API extension:
src/modules/auth/myAuth.tsx - Frontend module:
src/modules/auth/index.tsx - Sign-in page:
src/modules/signInPage/index.tsx - App installation:
src/App.tsx
Steps:
- Define API ref (see
custom-oidc-ref.ts) - Create API extension with
ApiBlueprint.make()(seecustom-oidc-implementation.tsx) - Bundle into frontend module with
createFrontendModule() - Configure sign-in page with
SignInPageBlueprint - Install modules in
createApp({ features: [] })
Backend:
- Create backend authenticator (implements PKCE, etc.)
- Register provider with
authProvidersExtensionPoint - Configure
auth.providers.{provider}in app-config.yaml
Key Points:
- Provider IDs must match (frontend, backend, config)
- OAuth2.create() is generic (works with any provider)
- PKCE is backend-only (frontend code is identical)
Pattern 2: Creating Custom Utility API
Files Needed:
- API contract:
plugins/my-plugin-react/src/api.ts - API implementation:
plugins/my-plugin/src/api/MyApiImpl.ts - API extension:
plugins/my-plugin/src/alpha.tsx - Plugin export:
plugins/my-plugin/src/index.ts
Steps:
- Define interface and API ref (see
creating-api-ref.ts) - Implement interface (see
api-implementation.tsx) - Create API extension with
ApiBlueprint.make() - Export from plugin as feature
- Install plugin in app
Key Points:
- APIs can depend on other APIs
- Use
-reactpackage for shared API contracts - ApiBlueprint handles extension data automatically
Pattern 3: Creating Extension with Configuration
Key Concepts:
- Use Zod for schema (
z => z.string().default('...')) - Config passed to factory via
{ config }parameter - Configure in
app-config.yamlunderapp.extensions
Example:
const myExtension = createExtension({
config: {
schema: {
title: z => z.string().default('Default Title'),
enabled: z => z.boolean().default(true),
},
},
factory({ config }) {
return [
coreExtensionData.reactElement(
<MyComponent title={config.title} />
),
];
},
});
Troubleshooting
Example Doesn't Work
-
Check Backstage version
- Examples require v1.42.0+
- Run:
yarn backstage-cli versions:check
-
Check imports
- Verify package names match your app
- Check for typos in imports
-
Check file structure
- Ensure files are in correct locations
- Verify module exports
-
Enable debug logging
# app-config.yaml
app:
debug: true -
Check browser console
- Look for extension registration messages
- Check for API ref resolution errors
-
Use app visualizer
yarn add @backstage/plugin-app-visualizer
# Navigate to /visualizer
Type Errors
-
Update dependencies
yarn upgrade @backstage/frontend-plugin-api @backstage/core-plugin-api -
Check TypeScript version
- Requires TypeScript 5.0+
-
Verify imports
- Some types moved between packages in v1.42.0
Auth Flow Errors
-
Provider ID mismatch
- Frontend:
provider: { id: 'my-provider' } - Backend:
providerId: 'my-provider' - Config:
auth.providers.my-provider
- Frontend:
-
Callback URL
- Verify IdP callback:
{backend.baseUrl}/api/auth/{provider}/handler/frame - Check CORS configuration
- Verify IdP callback:
-
Token validation
- Check backend logs
- Verify IdP token format
Getting Help
- Documentation: See
../new-frontend-system/INDEX.md - Auth Deep Dive: See
../new-frontend-system/05-auth-providers.md - GitHub Issues: https://github.com/backstage/backstage/issues
- Discord: https://discord.gg/backstage-687207715902193673 (#support)
Contributing
Found a bug in an example or have a suggestion?
- Open an issue: GitHub Issues
- Create a PR with fix/improvement
- Include test results if applicable
Example Status
| Example | Status | Tested | Notes |
|---|---|---|---|
| custom-oidc-ref.ts | ✅ Complete | ⚠️ Pattern Verified | Extracted from working implementation |
| custom-oidc-implementation.tsx | ✅ Complete | ⚠️ Pattern Verified | Based on Backstage core patterns |
| oauth2-create-pattern.tsx | ✅ Complete | ⚠️ Pattern Verified | Simplified from source code |
| (other examples) | 🚧 Coming Soon | ❌ Not Yet | Planned for future updates |
Legend:
- ✅ Complete: Example is ready to use
- 🚧 Coming Soon: Planned but not yet created
- ⚠️ Pattern Verified: Pattern is correct, needs full integration testing
- ✅ Fully Tested: Tested in real Backstage app
- ❌ Not Yet: Not tested yet
Next Steps
- Start with Auth Examples if implementing custom OIDC/PKCE
- Read accompanying documentation in
../new-frontend-system/ - Test in your environment using local testing method
- Report issues if examples don't work as expected
- Share feedback on what examples would be most helpful
Related Documentation:
- INDEX.md - Main documentation hub
- 05-auth-providers.md - Auth provider deep dive
- 04-utility-apis.md - Utility API patterns