@opengovsg/mockpass 4.5.0 → 4.5.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -7,6 +7,8 @@ on:
7
7
  jobs:
8
8
  publish-npm:
9
9
  runs-on: ubuntu-latest
10
+ permissions:
11
+ id-token: write
10
12
  steps:
11
13
  - uses: actions/checkout@v4
12
14
  - uses: actions/setup-node@v3
@@ -15,10 +17,10 @@ jobs:
15
17
  cache: 'npm'
16
18
  cache-dependency-path: '**/package-lock.json'
17
19
  registry-url: https://registry.npmjs.org/
20
+ - name: Update npm
21
+ run: npm install -g npm@latest # Get the latest npm for OIDC support
18
22
  - run: npm ci
19
23
  - run: npm publish --access public
20
- env:
21
- NODE_AUTH_TOKEN: ${{secrets.NPM_TOKEN}}
22
24
  publish-docker:
23
25
  runs-on: ubuntu-latest
24
26
  steps:
package/README.md CHANGED
@@ -21,7 +21,7 @@ Configure your application to point to the following endpoints:
21
21
 
22
22
  - http://localhost:5156/singpass/v2/.well-known/openid-configuration
23
23
  - http://localhost:5156/singpass/v2/.well-known/keys
24
- - http://localhost:5156/singpass/v2/authorize
24
+ - http://localhost:5156/singpass/v2/auth
25
25
  - http://localhost:5156/singpass/v2/token
26
26
 
27
27
  Configure your application (or MockPass) with keys:
@@ -45,7 +45,7 @@ Configure your application to point to the following endpoints:
45
45
 
46
46
  - http://localhost:5156/corppass/v2/.well-known/openid-configuration
47
47
  - http://localhost:5156/corppass/v2/.well-known/keys
48
- - http://localhost:5156/corppass/v2/authorize
48
+ - http://localhost:5156/corppass/v2/auth
49
49
  - http://localhost:5156/corppass/v2/token
50
50
 
51
51
  Configure your application (or MockPass) with keys:
package/lib/assertions.js CHANGED
@@ -70,6 +70,7 @@ const oidc = {
70
70
  ...Object.keys(myinfo.v3.personas).map((nric) => ({
71
71
  nric,
72
72
  uuid: myinfo.v3.personas[nric].uuid.value,
73
+ claims: myinfo.v3.personas[nric],
73
74
  })),
74
75
  ],
75
76
  corpPass: [
@@ -157,7 +157,7 @@ function config(app, { showLoginPage, isStateless }) {
157
157
  const defaultProfile =
158
158
  profiles.find((p) => p.nric === process.env.MOCKPASS_NRIC) || profiles[0]
159
159
 
160
- app.get(`/${idp.toLowerCase()}/v2/authorize`, (req, res) => {
160
+ app.get(`/${idp.toLowerCase()}/v2/auth`, (req, res) => {
161
161
  const {
162
162
  scope: scopes,
163
163
  response_type,
@@ -227,7 +227,7 @@ function config(app, { showLoginPage, isStateless }) {
227
227
  const response = render(LOGIN_TEMPLATE, {
228
228
  values,
229
229
  customProfileConfig: {
230
- endpoint: `/${idp.toLowerCase()}/v2/authorize/custom-profile`,
230
+ endpoint: `/${idp.toLowerCase()}/v2/auth/custom-profile`,
231
231
  showUuid: true,
232
232
  showUen: idp === 'corpPass',
233
233
  redirectURI,
@@ -250,7 +250,7 @@ function config(app, { showLoginPage, isStateless }) {
250
250
  }
251
251
  })
252
252
 
253
- app.get(`/${idp.toLowerCase()}/v2/authorize/custom-profile`, (req, res) => {
253
+ app.get(`/${idp.toLowerCase()}/v2/auth/custom-profile`, (req, res) => {
254
254
  const { nric, uuid, uen, redirectURI, state, nonce } = req.query
255
255
 
256
256
  const profile = { nric, uuid }
@@ -423,14 +423,9 @@ function config(app, { showLoginPage, isStateless }) {
423
423
  redirect_uri: redirectURI,
424
424
  })
425
425
 
426
- const { idTokenClaims } = await assertions.oidc.create[idp](
427
- profile,
428
- iss,
429
- aud,
430
- nonce,
431
- )
432
-
433
- const accessToken = authCode
426
+ const { idTokenClaims, accessToken } = await assertions.oidc.create[
427
+ idp
428
+ ](profile, iss, aud, nonce, authCode)
434
429
 
435
430
  // Step 3: Sign ID token with ASP signing key
436
431
  const aspKeyset = JSON.parse(aspSecret)
@@ -517,7 +512,7 @@ function config(app, { showLoginPage, isStateless }) {
517
512
  // Note: does not support backchannel auth
518
513
  const data = {
519
514
  issuer: baseUrl,
520
- authorization_endpoint: `${baseUrl}/authorize`,
515
+ authorization_endpoint: `${baseUrl}/auth`,
521
516
  jwks_uri: `${baseUrl}/.well-known/keys`,
522
517
  response_types_supported: ['code'],
523
518
  scopes_supported: ['openid'],
@@ -551,6 +546,9 @@ function config(app, { showLoginPage, isStateless }) {
551
546
  ...data['scopes_supported'],
552
547
  'uinfin',
553
548
  'name',
549
+ 'email',
550
+ 'mobileno',
551
+ 'regadd',
554
552
  ]
555
553
  data['userinfo_endpoint'] = `${baseUrl}/userinfo`
556
554
  data['userinfo_signing_alg_values_supported'] = ['ES256']
@@ -573,16 +571,27 @@ function config(app, { showLoginPage, isStateless }) {
573
571
 
574
572
  const authCode = extractBearerTokenFromHeader(headers, res)
575
573
 
576
- const { profile, scopes, clientId } = lookUpByAuthCode(authCode, {
574
+ const found = lookUpByAuthCode(authCode, {
577
575
  isStateless,
578
576
  })
579
577
 
578
+ if (!found || !found.scopes) {
579
+ return res.status(400).send({
580
+ error: 'invalid_request',
581
+ error_description:
582
+ 'Myinfo profile has yet to be provisioned for the user',
583
+ })
584
+ }
585
+
586
+ const {
587
+ profile: { uuid },
588
+ scopes,
589
+ clientId,
590
+ } = found
580
591
  const scopesArr = scopes.split(' ')
581
592
  console.log('userinfo scopes: ', scopesArr)
582
593
 
583
- const { uuid } = profile
584
- const { nric } = assertions.oidc.singPass.find((p) => p.uuid === uuid)
585
- const name = `USER ${nric}`
594
+ const profile = assertions.oidc.singPass.find((p) => p.uuid === uuid)
586
595
 
587
596
  const iss = `${protocol}://${host}/${idp.toLowerCase()}/v2`
588
597
  const aud = clientId
@@ -599,10 +608,14 @@ function config(app, { showLoginPage, isStateless }) {
599
608
  iat,
600
609
  }
601
610
 
602
- const claimMap = { uinfin: nric, name }
611
+ const claimMap = profile.claims || {
612
+ uinfin: makeClaim(profile.nric),
613
+ name: makeClaim(`USER ${profile.nric}`),
614
+ }
615
+
603
616
  for (const [claim, value] of Object.entries(claimMap)) {
604
617
  if (scopesArr.includes(claim)) {
605
- attachClaim(userinfoPayload, claim, value)
618
+ userinfoPayload[claim] = value
606
619
  }
607
620
  }
608
621
 
@@ -647,7 +660,7 @@ function config(app, { showLoginPage, isStateless }) {
647
660
  alg: rpEncryptionKey.alg,
648
661
  typ: 'JWT',
649
662
  kid: rpEncryptionKey.kid,
650
- enc: 'A256CBC-HS512',
663
+ enc: 'A256GCM',
651
664
  cty: 'JWT',
652
665
  }
653
666
 
@@ -739,13 +752,11 @@ const extractBearerTokenFromHeader = (headers, res) => {
739
752
  return tokenParts[1]
740
753
  }
741
754
 
742
- const attachClaim = (payload, key, value) => {
743
- payload[key] = {
744
- lastupdated: '2023-03-23',
745
- source: '1',
746
- classification: 'C',
747
- value,
748
- }
749
- }
755
+ const makeClaim = (value) => ({
756
+ lastupdated: '2023-03-23',
757
+ source: '1',
758
+ classification: 'C',
759
+ value,
760
+ })
750
761
 
751
762
  module.exports = config
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@opengovsg/mockpass",
3
- "version": "4.5.0",
3
+ "version": "4.5.2",
4
4
  "description": "A mock SingPass/CorpPass server for dev purposes",
5
5
  "main": "app.js",
6
6
  "bin": {