8000 1.12.1 introduced a circular dependency · Issue #6938 · hedgedoc/hedgedoc · GitHub
[go: up one dir, main page]

Skip to content

1.12.1 introduced a circular dependency #6938

Open
adfinis/helm-charts
#2094

Description

@d--j

Description

Since 1.12.1, every OAuth2 (and presumably every other passport-based social/SSO) login fails with a 500 after the provider redirects back to /auth/oauth2/callback. Email/password login is unaffected. 1.12.0 works fine with the same config.

The cause is a circular import introduced in 3219964 ("fix(login): avoid email check using timing attack"), which added this to lib/models/user.js:

const { verifyPassword } = require('../web/auth/utils')

This results in the following load order:

  1. lib/models/index.js starts loading and requires lib/models/user.js
  2. user.js now requires lib/web/auth/utils.js
  3. utils.js runs const models = require('../../models') at module load, while models/index.js is still loading, so it receives the partial (empty) exports object
  4. models/index.js finishes with module.exports = db, but utils.js keeps the stale object

As a result, models.User is undefined in passportGeneralCallback, and the callback crashes on models.User.findOrCreate.

Steps to reproduce

  1. Run quay.io/hedgedoc/hedgedoc:1.12.1 with generic OAuth2 configured (Keycloak in my case)
  2. Click "Sign in via OAuth2" and authenticate at the provider
  3. The callback returns HTTP 500

Expected behaviour

The user is logged in, as on 1.12.0.

Logs

With `NODE_OPTIONS=--trace-warnings`:


Nov 04 23:26:30 pad docker[26393]: 2026-11-04T22:26:30.308Z info:         84.151.78.234 - - [04/Nov/2026:22:26:30 +0000] "GET /auth/oauth2 HTTP/1.1" 302 0 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.0.0 Safari/537.36"
Nov 04 23:26:30 pad docker[26393]: (node:1) Warning: Accessing non-existent property 'User' of module exports inside circular dependency
Nov 04 23:26:30 pad docker[26393]:     at emitCircularRequireWarning (node:internal/modules/cjs/loader:1044:11)
Nov 04 23:26:30 pad docker[26393]:     at Object.get (node:internal/modules/cjs/loader:1060:5)
Nov 04 23:26:30 pad docker[26393]:     at OAuth2CustomStrategy.callback [as _verify] (file:///hedgedoc/lib/web/auth/utils.js:12:10)
Nov 04 23:26:30 pad docker[26393]:     at /hedgedoc/node_modules/passport-oauth2/lib/strategy.js:205:24
Nov 04 23:26:30 pad docker[26393]:     at /hedgedoc/lib/web/auth/oauth2/index.js:131:5
Nov 04 23:26:30 pad docker[26393]:     at passBackControl (/hedgedoc/node_modules/passport-oauth2/node_modules/oauth/lib/oauth2.js:134:9)
Nov 04 23:26:30 pad docker[26393]:     at IncomingMessage.<anonymous> (/hedgedoc/node_modules/passport-oauth2/node_modules/oauth/lib/oauth2.js:157:7)
Nov 04 23:26:30 pad docker[26393]:     at IncomingMessage.emit (node:events:526:24)
Nov 04 23:26:30 pad docker[26393]:     at endReadableNT (node:internal/streams/readable:1783:12)
Nov 04 23:26:30 pad docker[26393]:     at process.processTicksAndRejections (node:internal/process/task_queues:90:21)
Nov 04 23:26:30 pad docker[26393]: TypeError: Cannot read properties of undefined (reading 'findOrCreate')
Nov 04 23:26:30 pad docker[26393]:     at OAuth2CustomStrategy.callback [as _verify] (file:///hedgedoc/lib/web/auth/utils.js:12:15)
Nov 04 23:26:30 pad docker[26393]:     at /hedgedoc/node_modules/passport-oauth2/lib/strategy.js:205:24
Nov 04 23:26:30 pad docker[26393]:     at /hedgedoc/lib/web/auth/oauth2/index.js:131:5
Nov 04 23:26:30 pad docker[26393]:     at passBackControl (/hedgedoc/node_modules/passport-oauth2/node_modules/oauth/lib/oauth2.js:134:9)
Nov 04 23:26:30 pad docker[26393]:     at IncomingMessage.<anonymous> (/hedgedoc/node_modules/passport-oauth2/node_modules/oauth/lib/oauth2.js:157:7)
Nov 04 23:26:30 pad docker[26393]:     at IncomingMessage.emit (node:events:526:24)
Nov 04 23:26:30 pad docker[26393]:     at endReadableNT (node:internal/streams/readable:1783:12)
Nov 04 23:26:30 pad docker[26393]:     at process.processTicksAndRejections (node:internal/process/task_queues:90:21)
Nov 04 23:26:30 pad docker[26393]: 2026-11-04T22:26:30.575Z info:         84.151.78.234 - - [04/Nov/2026:22:26:30 +0000] "GET /auth/oauth2/callback?state=… HTTP/1.1" 500 148 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.0.0 Safari/537.36"

Config

-e CMD_DB_URL=postgres://hedgedoc:xxx@database:5432/hedgedoc \
    -e CMD_DOMAIN=xxx \
    -e CMD_URL_ADDPORT=false \
    -e CMD_PROTOCOL_USESSL=true \
     -e CMD_OAUTH2_USER_PROFILE_URL=https://xxx/realms/xxx/protocol/openid-connect/userinfo  -e CMD_OAUTH2_USER_PROFILE_USERNAME_ATTR=preferred_username  -e CMD_OAUTH2_USER_PROFILE_DISPLAY_NAME_ATTR=name  -e CMD_OAUTH2_USER_PROFILE_EMAIL_ATTR=email  -e CMD_OAUTH2_TOKEN_URL=https://xxx/realms/xxx/protocol/openid-connect/token  -e CMD_OAUTH2_AUTHORIZATION_URL=https://xxx/realms/xxx/protocol/openid-connect/auth  -e CMD_OAUTH2_CLIENT_ID=pad  -e CMD_OAUTH2_CLIENT_SECRET=xxx  -e CMD_OAUTH2_PROVIDERNAME="xxx"  -e CMD_OAUTH2_SCOPE="openid email profile"  -e CMD_EMAIL=false  -e CMD_ALLOW_ANONYMOUS=false  -e CMD_ALLOW_ANONYMOUS_EDITS=true  -e CMD_SESSION_SECRET=xxx  -e CMD_ENABLE_UPLOADS=registered \
-e NODE_OPTIONS=--trace-warnings

Your Setup

  • HedgeDoc version: 1.12.1 (official image quay.io/hedgedoc/hedgedoc:1.12.1)
  • NodeJS version: the one shipped in the image
  • Database: PostgreSQL
  • Auth: generic OAuth2 (Keycloak)

Additional context

Possible fixes:

  • Move verifyPassword into a module that doesn't depend on models (e.g. lib/utils/password.js) and import it from both lib/models/user.js and lib/web/auth/email/index.js, or
  • Resolve models lazily in lib/web/auth/utils.js.

Workaround I'm using right now (bind-mounted patched utils.js), replacing line 7:

const models = new Proxy({}, { get: (_, prop) => require('../../models')[prop] })

Rolling back to 1.12.0 also works, but that drops the security fixes in 1.12.1, so I'd rather not.

Activity

  1. self-assigned this
    on Nov 5, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions

    0