Skip to content
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 46 additions & 1 deletion plugins/backstage-plugin-coder-backend/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,47 @@
## Features

- Management of OAuth2 state for requests sent from the Backstage backend.
- Provides OAuth callback endpoint at `/api/coder/oauth/callback`

## Installing the plugin to support oauth2

### For the New Backend System

If you're using Backstage's new backend system (v1.20+), follow these steps:

1. Run the following command from your Backstage app to install the plugin:
```bash
yarn --cwd packages/backend add @coder/backstage-plugin-coder-backend
```
2. Add the module to your backend in `packages/backend/src/index.ts`:
```ts
backend.add(import('@coder/backstage-plugin-coder-backend'));
```
3. [If you haven't already, be sure to register Backstage as an oauth app through Coder](https://coder.com/docs/admin/integrations/oauth2-provider).

When registering the OAuth application, use the following callback URL format:
```
https://backstage.example.com/api/coder/oauth/callback
```
Replace `backstage.example.com` with your actual Backstage domain.

4. Add the following values to one of your `app-config.yaml` files:
```yaml
coder:
deployment:
# Change the value to match your Coder deployment
accessUrl: https://dev.coder.com
oauth:
clientId: oauth2-client-id-goes-here
# The client secret isn't used by the frontend plugin, but the backend
# plugin needs it for oauth functionality to work
clientSecret: oauth2-secret-goes-here
```

Note that the `clientSecret` value is given `secret`-level visibility, and will never be logged anywhere by Backstage.

### For the Legacy Backend System

1. Run the following command from your Backstage app to install the plugin:
```bash
yarn --cwd packages/app add @coder/backstage-plugin-coder
Expand All @@ -25,14 +63,21 @@
4. Register the plugin's oauth route with Backstage from inside the same `main` function:
```ts
apiRouter.use(
'/auth/coder',
'/coder',
await createCoderRouter({
logger: coderEnv.logger,
config: coderEnv.config,
}),
);
```
5. [If you haven't already, be sure to register Backstage as an oauth app through Coder](https://coder.com/docs/admin/integrations/oauth2-provider).

When registering the OAuth application, use the following callback URL format:
```
https://backstage.example.com/api/coder/oauth/callback
```
Replace `backstage.example.com` with your actual Backstage domain.

6. Add the following values to one of your `app-config.yaml` files:
```yaml
coder:
Expand Down
1 change: 1 addition & 0 deletions plugins/backstage-plugin-coder-backend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
},
"dependencies": {
"@backstage/backend-common": "^0.20.1",
"@backstage/backend-plugin-api": "^0.6.0",
"@backstage/config": "^1.1.1",
"@backstage/errors": "^1.2.3",
"@types/express": "*",
Expand Down
4 changes: 4 additions & 0 deletions plugins/backstage-plugin-coder-backend/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,8 @@
* @packageDocumentation
*/

// Legacy API for old backend system
export { createRouter } from './service/router';

// New backend system module
export { default } from './module';
50 changes: 50 additions & 0 deletions plugins/backstage-plugin-coder-backend/src/module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import {
coreServices,
createBackendPlugin,
} from '@backstage/backend-plugin-api';
import { createRouter } from './service/router';

/**
* Coder OAuth backend plugin for the new Backstage backend system.
*
* This plugin provides OAuth authentication routes for Coder at /api/coder/oauth/callback.
*
* @public
*/
export default createBackendPlugin({
pluginId: 'coder',
register(env) {
env.registerInit({
deps: {
logger: coreServices.logger,
config: coreServices.rootConfig,
httpRouter: coreServices.httpRouter,
},
async init({ logger, config, httpRouter }) {
logger.info('Initializing Coder OAuth plugin');

const router = await createRouter({
logger: logger as any,
config,
});

// Allow unauthenticated access to OAuth routes
httpRouter.addAuthPolicy({
path: '/oauth',
allow: 'unauthenticated',
});

httpRouter.addAuthPolicy({
path: '/health',
allow: 'unauthenticated',
});

// Register the router (will be mounted at /api/coder)
httpRouter.use(router);

logger.info('Coder OAuth plugin initialized at /api/coder');
},
});
},
});

Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ export async function createRouter(
const clientSecret = coderConfig?.getString('oauth.clientSecret') || '';
const redirectUri = `${req.protocol}://${req.get(
'host',
)}/api/auth/coder/oauth/callback`;
)}/api/coder/oauth/callback`;

let tokenResponse: AxiosResponse<{ access_token?: string }, unknown>;
try {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ export const CoderAuthInputForm = () => {
state: btoa(JSON.stringify({ returnTo: window.location.pathname })),
response_type: 'code',
client_id: clientId,
redirect_uri: `${backendUrl}/api/auth/coder/oauth/callback`,
redirect_uri: `${backendUrl}/api/coder/oauth/callback`,
});

const oauthUrl = `${
Expand Down
Loading