backstage: 🐛 Bug Report: Authentication with Oaut2-proxy development environment

📜 Description

Enable backstage authentication with oauth2-proxy.

👍 Expected behavior

Configure user authentication with keycloak and oauth2-proxy.

👎 Actual Behavior with Screenshots

Error

Request URL: http://localhost:7007/api/auth/oauth2Proxy/refresh Request Method: GET Status Code: 401 Unauthorized

👟 Reproduction steps

1.- Keycloak

  • Start local keycloak in docker with: docker run -p 9990:8080 -e KEYCLOAK_USER=admin -e KEYCLOAK_PASSWORD=admin jboss/keycloak
  • Add new Backstage realm and create user.

2.- Oauth2-Proxy.

http_address = "127.0.0.1:4180"

provider = "keycloak"
login_url = "http://localhost:9990/auth/realms/backstage/protocol/openid-connect/auth"
redeem_url = "http://localhost:9990/auth/realms/backstage/protocol/openid-connect/token"
profile_url = "http://localhost:9990/auth/realms/backstage/protocol/openid-connect/userinfo"
validate_url = "http://localhost:9990/auth/realms/backstage/protocol/openid-connect/userinfo"
oidc_issuer_url = "http://localhost:9990/auth/realms/backstage"

client_id = "oauth2-proxy"
client_secret = "B6U0bbjTB0SdqzaUJVCpNh3y2wMFkgYI"

redirect_url = "http://localhost:4180/oauth2/callback"

upstreams = [
    "http://127.0.0.1:3000/"
]

request_logging = true

pass_basic_auth = true
pass_user_headers = true
pass_host_header = true 

email_domains = [
    "*"
]

pass_access_token = true
ssl_insecure_skip_verify = false
cookie_secret = "lLYcG3L1khAS9Yz8hXb7mia1wSDk_eCDQFzl_Yx2rA4="
cookie_secure = false
set_authorization_header = "true"
pass_authorization_header = "true"
reverse_proxy = "true"
scope = "email"
whitelist_domains = "*"
skip_provider_button = "true"
set_xauthrequest = "true"
  • run command:
./oauth2-proxy \
    --config=./oauth2_proxy.cfg

3.- Backstage

  • I started a new project with the command: npx @backstage/create-app
  • the following files have been modified:

app-config.yaml:

<SNIP>
...
auth:
  providers:
    oauth2Proxy: {}

App.tsx:

<SNIP>
...

const app = createApp({
  ...
  components: {
    SignInPage: props => (
      <ProxiedSignInPage {...props} provider="oauth2Proxy" />
    ),
  },
});

<SNIP>

auth.ts

<SNIP>
...

export default async function createPlugin(
  env: PluginEnvironment,
): Promise<Router> {
  return await createRouter({
    logger: env.logger,
    config: env.config,
    database: env.database,
    discovery: env.discovery,
    tokenManager: env.tokenManager,
    providerFactories: {
      ...defaultAuthProviderFactories,

      oauth2Proxy: providers.oauth2Proxy.create({
        signIn: {
          async resolver(info, ctx) {
            const name = result.getHeader('x-forwarded-user');
            if (!name) {
              throw new Error('Request did not contain a user')
            }

            // Create stub user
            const userEntityRef = stringifyEntityRef({
              kind: 'User',
              name: name,
              namespace: DEFAULT_NAMESPACE,
            });

            return ctx.issueToken({
              claims: {
                sub: userEntityRef,
                ent: [userEntityRef],
              },
            });

          },
        },
      }),

...
<SNIP>
  • run command:
yarn dev

4.- Test

  • Enter http:localhost4180
  • Login with user and password previously configured in keycloak.

📃 Provide the context for the Bug.

No response

🖥️ Your Environment

OS: Darwin 22.3.0 - darwin/x64 node: v16.14.2 yarn: 1.22.19 cli: 0.22.3 (installed) backstage: 1.11.0

Dependencies: @backstage/app-defaults 1.2.0 @backstage/backend-app-api 0.4.0 @backstage/backend-common 0.18.2 @backstage/backend-dev-utils 0.1.0 @backstage/backend-plugin-api 0.4.0 @backstage/backend-tasks 0.4.3 @backstage/catalog-client 1.3.1 @backstage/catalog-model 1.2.0 @backstage/cli-common 0.1.11 @backstage/cli 0.22.3 @backstage/config-loader 1.1.8 @backstage/config 1.0.6 @backstage/core-app-api 1.5.0 @backstage/core-components 0.12.4 @backstage/core-plugin-api 1.4.0 @backstage/dev-utils 1.0.12 @backstage/errors 1.1.4 @backstage/eslint-plugin 0.1.1 @backstage/integration-aws-node 0.1.1 @backstage/integration-react 1.1.10 @backstage/integration 1.4.2 @backstage/plugin-api-docs 0.9.0 @backstage/plugin-app-backend 0.3.42 @backstage/plugin-auth-backend 0.18.0 @backstage/plugin-auth-node 0.2.11 @backstage/plugin-catalog-backend 1.7.2 @backstage/plugin-catalog-common 1.0.11 @backstage/plugin-catalog-graph 0.2.27 @backstage/plugin-catalog-import 0.9.5 @backstage/plugin-catalog-node 1.3.3 @backstage/plugin-catalog-react 1.3.0 @backstage/plugin-catalog 1.8.0 @backstage/plugin-github-actions 0.5.15 @backstage/plugin-org 0.6.5 @backstage/plugin-permission-common 0.7.3 @backstage/plugin-permission-node 0.7.5 @backstage/plugin-permission-react 0.4.10 @backstage/plugin-proxy-backend 0.2.36 @backstage/plugin-scaffolder-backend 1.11.0 @backstage/plugin-scaffolder-common 1.2.5 @backstage/plugin-scaffolder-node 0.1.0 @backstage/plugin-scaffolder-react 1.1.0 @backstage/plugin-scaffolder 1.11.0 @backstage/plugin-search-backend-module-pg 0.5.3 @backstage/plugin-search-backend-node 1.1.3 @backstage/plugin-search-backend 1.2.3 @backstage/plugin-search-common 1.2.1 @backstage/plugin-search-react 1.5.0 @backstage/plugin-search 1.1.0 @backstage/plugin-tech-radar 0.6.1 @backstage/plugin-techdocs-backend 1.5.3 @backstage/plugin-techdocs-module-addons-contrib 1.0.10 @backstage/plugin-techdocs-node 1.5.0 @backstage/plugin-techdocs-react 1.1.3 @backstage/plugin-techdocs 1.5.0 @backstage/plugin-user-settings 0.7.0 @backstage/release-manifests 0.0.8 @backstage/test-utils 1.2.5 @backstage/theme 0.2.17 @backstage/types 1.0.2 @backstage/version-bridge 1.0.3

👀 Have you spent some time to check if this bug has been raised before?

  • I checked and didn’t find similar issue

🏢 Have you read the Code of Conduct?

Are you willing to submit PR?

None

About this issue

  • Original URL
  • State: closed
  • Created a year ago
  • Comments: 15 (3 by maintainers)

Most upvoted comments

I was running into the same issue in my local environment where headers were not passed to backend and found this issue. I was able to get it working with Keycloak + oAuth2-proxy + Backstage. I wanted to share what I did in case others run into the same issue. I found the notes found in the yaml file to be very useful.

  1. CORS origin must be updated. Otherwise, request will be blocked by your browser (at least in Firefox).
cors:
  origin: http://localhost:4180
  1. Backend base URL must also be updated to make sure necessary headers are included in requests.
backend:
  baseUrl: http://localhost:4180
  1. Make sure upstreams in oAuth2-proxy is setup correctly
OAUTH2_PROXY_UPSTREAMS=http://localhost:3000,http://localhost:7007/api/

I was running into the same issue in my local environment where headers were not passed to backend and found this issue. I was able to get it working with Keycloak + oAuth2-proxy + Backstage. I wanted to share what I did in case others run into the same issue. I found the notes found in the yaml file to be very useful.

  1. CORS origin must be updated. Otherwise, request will be blocked by your browser (at least in Firefox).
cors:
  origin: http://localhost:4180
  1. Backend base URL must also be updated to make sure necessary headers are included in requests.
backend:
  baseUrl: http://localhost:4180
  1. Make sure upstreams in oAuth2-proxy is setup correctly
OAUTH2_PROXY_UPSTREAMS=http://localhost:3000,http://localhost:7007/api/

thank you very much @nabuskey for sharing this configuration. I was able to test it and it works!