Skip to content

Bug with NodeJS Demo #46

@ianhohoho

Description

@ianhohoho

Upon pulling the repo and doing npm install and npm start without making additional changes, clicking on login on the staging singpass leads to the following error:

    at e (/Users/ianho/Desktop/demo-app/examples/nodejs/node_modules/openid-client/src/index.ts:911:10)
    at errorHandler (/Users/ianho/Desktop/demo-app/examples/nodejs/node_modules/openid-client/src/index.ts:932:15)
    at Module.fetchUserInfo (/Users/ianho/Desktop/demo-app/examples/nodejs/node_modules/openid-client/src/index.ts:4100:5)
    at process.processTicksAndRejections (node:internal/process/task_queues:105:5)
    at async handleSingpassCallback (/Users/ianho/Desktop/demo-app/examples/nodejs/src/router.ts:150:22)
    at async session (/Users/ianho/Desktop/demo-app/examples/nodejs/node_modules/koa-session/src/index.ts:216:7)
    at async serve (/Users/ianho/Desktop/demo-app/examples/nodejs/node_modules/koa-static/index.js:53:9)
    at async logger (/Users/ianho/Desktop/demo-app/examples/nodejs/node_modules/koa-logger/index.js:130:7) {
  code: 'OAUTH_RESPONSE_IS_NOT_CONFORM',
  [cause]: Response {
    status: 400,
    statusText: 'Bad Request',
    headers: Headers {
      date: 'Sat, 28 Feb 2026 13:01:17 GMT',
      'content-type': 'application/jwt; charset=utf-8',
      'content-length': '196',
      connection: 'keep-alive',
      'content-security-policy': "default-src 'self';base-uri 'self';font-src 'self' https: data:;form-action 'self';frame-ancestors 'self';img-src 'self' data:;object-src 'none';script-src 'self';script-src-attr 'none';style-src 'self' https: 'unsafe-inline';upgrade-insecure-requests",
      'cross-origin-opener-policy': 'unsafe-none',
      'cross-origin-resource-policy': 'same-origin',
      'origin-agent-cluster': '?1',
      'referrer-policy': 'no-referrer',
      'strict-transport-security': 'max-age=15552000; includeSubDomains',
      'x-content-type-options': 'nosniff',
      'x-dns-prefetch-control': 'off',
      'x-download-options': 'noopen',
      'x-frame-options': 'SAMEORIGIN',
      'x-permitted-cross-domain-policies': 'none',
      'x-xss-protection': '0',
      'x-singpass-request-id': 'b0c9a6c9-67b9-435b-9a45-eff15cdac713',
      vary: 'Origin',
      'access-control-allow-credentials': 'true',
      'access-control-expose-headers': 'X-Singpass-Request-Id,Retry-After,WWW-Authenticate',
      etag: 'W/"c4-9OmEJFKigdxR/lSvOSX3QSycMNw"',
      'server-timing': 'cfReqDur;dur=37.104',
      'cf-team': '2d45efe1b4000180b29f5ea400000001'
    },
    body: ReadableStream { locked: false, state: 'readable', supportsBYOB: true },
    bodyUsed: false,
    ok: false,
    redirected: false,
    type: 'basic',
    url: 'https://stg-id.singpass.gov.sg/fapi/userinfo'
  }

Upon inspection, the error is a 400 Bad Request from the userinfo endpoint (https://stg-id.singpass.gov.sg/fapi/userinfo).

Looking at router.ts:149-155, the code calls fetchUserInfo — but as the comment on line 149 says, this is only necessary if your app is a Myinfo app. If your app isn't registered as a Myinfo app on the Singpass side, the userinfo endpoint will reject the request.

Upon commeting out the following lines, the login works:

// const userInfo = await openidClient.fetchUserInfo(
    //   singpassConfig,
    //   tokens.access_token,
    //   idTokenClaims.sub,
    //   getDpopOptions()
    // );
    // console.log('This is the user info returned:');
    // console.log(userInfo);

For consideration to leave out to avoid confusion / unexpected errors given the ease expected of the demo app.

Metadata

Metadata

Assignees

No one assigned

    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