@carisls/sso-standard 1.0.6 → 1.1.0

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.
@@ -1,6 +1,6 @@
1
1
  const { tokenDecoderModule: decodeToken } = require('@carisls/sso-core');
2
2
 
3
- function refreshTokenModule (tokenValidator, encryptor) {
3
+ function refreshTokenModule (encryptor) {
4
4
  return async function (res, refreshToken, cookiesSecure) {
5
5
  // Process access token if returned
6
6
  const token = refreshToken.includes('.') ? decodeToken.data(refreshToken) : refreshToken;
@@ -1,3 +1,5 @@
1
+ const { stringify } = require('node:querystring');
2
+
1
3
  function logout (router, client, encryptor, logoutPath, afterLogoutPath) {
2
4
  router.get(logoutPath, async (req, res) => {
3
5
  let idToken = '';
@@ -9,16 +11,15 @@ function logout (router, client, encryptor, logoutPath, afterLogoutPath) {
9
11
  idToken = await encryptor.decrypt(req.cookies['x-session-id']);
10
12
  res.cookie('x-session-id', 'Removing...', { maxAge: 0 });
11
13
  }
12
- res.redirect(client.endSessionUrl({
13
14
 
15
+ res.redirect(`${client.issuer.end_session_endpoint}?${stringify({
14
16
  // redirect_uri for keycloak
15
17
  redirect_uri: `${req.protocol}://${req.headers.host}${afterLogoutPath}`,
16
18
 
17
19
  // id_token_hint and post_logout_redirect_uri for okta
18
20
  id_token_hint: idToken,
19
21
  post_logout_redirect_uri: `${req.protocol}://${req.headers.host}${afterLogoutPath}`
20
-
21
- }));
22
+ })}`);
22
23
  });
23
24
  }
24
25
 
@@ -1,13 +1,9 @@
1
1
  const { postForm } = require('@carisls/sso-core');
2
2
 
3
3
  function codeRequest (client) {
4
- const clientId = client.metadata.client_id;
5
- const clientSecret = client.metadata.client_secret || undefined;
6
- const url = client.issuer.token_endpoint;
7
-
8
- return (code, redirectUri) => postForm(url, {
9
- client_id: clientId,
10
- client_secret: clientSecret,
4
+ return (code, redirectUri) => postForm(client.issuer.token_endpoint, {
5
+ client_id: client.metadata.client_id,
6
+ client_secret: client.metadata.client_secret,
11
7
  grant_type: 'authorization_code',
12
8
  code,
13
9
  redirect_uri: redirectUri
@@ -18,19 +18,20 @@ function index (router, clientId, clientSecret, issuerSelector, encryptor, userM
18
18
  cookieParserModule(router);
19
19
 
20
20
  // Issuer Selector
21
- const keycloakIssuer = issuerSelector.providers[Object.keys(issuerSelector.providers)[0]].issuer;
22
21
  const tokenValidator = issuerSelector.providers[Object.keys(issuerSelector.providers)[0]].validator;
23
22
 
24
23
  // Instantiate client
25
- const client = new keycloakIssuer.Client({
26
- client_id: clientId,
27
- client_secret: clientSecret,
28
- response_types: ['code']
29
- });
24
+ const client = {
25
+ metadata: {
26
+ client_id: clientId,
27
+ client_secret: clientSecret
28
+ },
29
+ issuer: issuerSelector.providers[Object.keys(issuerSelector.providers)[0]].issuer
30
+ };
30
31
 
31
32
  // Instantiate token modules
32
33
  const accessTokenModule = accessTokenModule2(tokenValidator, encryptor, expOffset);
33
- const refreshTokenModule = refreshTokenModule2(tokenValidator, encryptor);
34
+ const refreshTokenModule = refreshTokenModule2(encryptor);
34
35
  const idTokenModule = idTokenModule2(encryptor); // id_token must be saved for Okta logout
35
36
 
36
37
  const codeRequestModule = codeRequestModule2(client);
@@ -45,7 +46,7 @@ function index (router, clientId, clientSecret, issuerSelector, encryptor, userM
45
46
  );
46
47
 
47
48
  // Handle return from standard SSO
48
- ssoModule(router, client,
49
+ ssoModule(router,
49
50
  paths?.sso || '/sso',
50
51
  codeRequestModule,
51
52
  accessTokenModule,
@@ -1,3 +1,5 @@
1
+ const { stringify } = require('node:querystring');
2
+
1
3
  function login (router, client, loginPath, ssoPath, afterLoginPath, groups = true) {
2
4
  router.get(loginPath, (req, res) => {
3
5
  // Set redirectTo
@@ -10,11 +12,13 @@ function login (router, client, loginPath, ssoPath, afterLoginPath, groups = tru
10
12
  scopes.push('groups');
11
13
 
12
14
  // Standard flow initiates directly
13
- res.redirect(client.authorizationUrl({
15
+ res.redirect(`${client.issuer.authorization_url}?${stringify({
16
+ client_id: client.metadata.client_id,
17
+ response_type: 'code',
18
+ scope: scopes.join(' '),
14
19
  redirect_uri: `${req.protocol}://${req.headers.host}${ssoPath}`,
15
- state: redirectTo ? Buffer.from(redirectTo).toString('hex') : undefined,
16
- scope: scopes.join(' ')
17
- }));
20
+ state: redirectTo ? Buffer.from(redirectTo).toString('base64url') : undefined
21
+ })}`);
18
22
  });
19
23
  }
20
24
 
@@ -1,10 +1,6 @@
1
1
  const { postForm } = require('@carisls/sso-core');
2
2
 
3
3
  function refreshRequest (router, client, encryptor, accessTokenModule, refreshTokenModule, idTokenModule) {
4
- const clientId = client.metadata.client_id;
5
- const clientSecret = client.metadata.client_secret || undefined;
6
- const url = client.issuer.token_endpoint;
7
-
8
4
  router.all('*', (req, res, next) => {
9
5
  // Check if SSO cookie is there
10
6
  if (req.cookies['x-session']?.length > 36 || req.token || !req.cookies['x-session-sso']) {
@@ -14,9 +10,9 @@ function refreshRequest (router, client, encryptor, accessTokenModule, refreshTo
14
10
 
15
11
  encryptor
16
12
  .decrypt(req.cookies['x-session-sso'])
17
- .then(token => postForm(url, {
18
- client_id: clientId,
19
- client_secret: clientSecret,
13
+ .then(token => postForm(client.issuer.token_endpoint, {
14
+ client_id: client.metadata.client_id,
15
+ client_secret: client.metadata.client_secret,
20
16
  grant_type: 'refresh_token',
21
17
  refresh_token: token
22
18
  }))
@@ -1,6 +1,6 @@
1
1
  const { HttpError } = require('@carisls/sso-core');
2
2
 
3
- function sso (router, client, ssoPath, codeRequestModule, accessTokenModule, refreshTokenModule, idTokenModule) {
3
+ function sso (router, ssoPath, codeRequestModule, accessTokenModule, refreshTokenModule, idTokenModule) {
4
4
  router.get(ssoPath, (req, res, next) => {
5
5
  if (!req.query.code) {
6
6
  next(new HttpError(500, req.query.error));
@@ -14,7 +14,7 @@ function sso (router, client, ssoPath, codeRequestModule, accessTokenModule, ref
14
14
  idTokenModule(res, tokens.id_token, req.protocol === 'https')
15
15
  ]))
16
16
  .then(() => {
17
- res.redirect(req.query.state ? Buffer.from(req.query.state, 'hex').toString('utf8') : '/');
17
+ res.redirect(req.query.state ? Buffer.from(req.query.state, 'base64url').toString('utf8') : '/');
18
18
  })
19
19
  .catch((err) => {
20
20
  next(err);
@@ -1,6 +1,6 @@
1
1
  import { tokenDecoderModule as decodeToken } from '@carisls/sso-core';
2
2
 
3
- function refreshTokenModule (tokenValidator, encryptor) {
3
+ function refreshTokenModule (encryptor) {
4
4
  return async function (res, refreshToken, cookiesSecure) {
5
5
  // Process access token if returned
6
6
  const token = refreshToken.includes('.') ? decodeToken.data(refreshToken) : refreshToken;
@@ -1,3 +1,5 @@
1
+ import { stringify } from 'node:querystring';
2
+
1
3
  function logout (router, client, encryptor, logoutPath, afterLogoutPath) {
2
4
  router.get(logoutPath, async (req, res) => {
3
5
  let idToken = '';
@@ -9,16 +11,15 @@ function logout (router, client, encryptor, logoutPath, afterLogoutPath) {
9
11
  idToken = await encryptor.decrypt(req.cookies['x-session-id']);
10
12
  res.cookie('x-session-id', 'Removing...', { maxAge: 0 });
11
13
  }
12
- res.redirect(client.endSessionUrl({
13
14
 
15
+ res.redirect(`${client.issuer.end_session_endpoint}?${stringify({
14
16
  // redirect_uri for keycloak
15
17
  redirect_uri: `${req.protocol}://${req.headers.host}${afterLogoutPath}`,
16
18
 
17
19
  // id_token_hint and post_logout_redirect_uri for okta
18
20
  id_token_hint: idToken,
19
21
  post_logout_redirect_uri: `${req.protocol}://${req.headers.host}${afterLogoutPath}`
20
-
21
- }));
22
+ })}`);
22
23
  });
23
24
  }
24
25
 
@@ -1,13 +1,9 @@
1
1
  import { postForm } from '@carisls/sso-core';
2
2
 
3
3
  function codeRequest (client) {
4
- const clientId = client.metadata.client_id;
5
- const clientSecret = client.metadata.client_secret || undefined;
6
- const url = client.issuer.token_endpoint;
7
-
8
- return (code, redirectUri) => postForm(url, {
9
- client_id: clientId,
10
- client_secret: clientSecret,
4
+ return (code, redirectUri) => postForm(client.issuer.token_endpoint, {
5
+ client_id: client.metadata.client_id,
6
+ client_secret: client.metadata.client_secret,
11
7
  grant_type: 'authorization_code',
12
8
  code,
13
9
  redirect_uri: redirectUri
@@ -18,19 +18,20 @@ function index (router, clientId, clientSecret, issuerSelector, encryptor, userM
18
18
  cookieParserModule(router);
19
19
 
20
20
  // Issuer Selector
21
- const keycloakIssuer = issuerSelector.providers[Object.keys(issuerSelector.providers)[0]].issuer;
22
21
  const tokenValidator = issuerSelector.providers[Object.keys(issuerSelector.providers)[0]].validator;
23
22
 
24
23
  // Instantiate client
25
- const client = new keycloakIssuer.Client({
26
- client_id: clientId,
27
- client_secret: clientSecret,
28
- response_types: ['code']
29
- });
24
+ const client = {
25
+ metadata: {
26
+ client_id: clientId,
27
+ client_secret: clientSecret
28
+ },
29
+ issuer: issuerSelector.providers[Object.keys(issuerSelector.providers)[0]].issuer
30
+ };
30
31
 
31
32
  // Instantiate token modules
32
33
  const accessTokenModule = accessTokenModule2(tokenValidator, encryptor, expOffset);
33
- const refreshTokenModule = refreshTokenModule2(tokenValidator, encryptor);
34
+ const refreshTokenModule = refreshTokenModule2(encryptor);
34
35
  const idTokenModule = idTokenModule2(encryptor); // id_token must be saved for Okta logout
35
36
 
36
37
  const codeRequestModule = codeRequestModule2(client);
@@ -45,7 +46,7 @@ function index (router, clientId, clientSecret, issuerSelector, encryptor, userM
45
46
  );
46
47
 
47
48
  // Handle return from standard SSO
48
- ssoModule(router, client,
49
+ ssoModule(router,
49
50
  paths?.sso || '/sso',
50
51
  codeRequestModule,
51
52
  accessTokenModule,
@@ -1,3 +1,5 @@
1
+ import { stringify } from 'node:querystring';
2
+
1
3
  function login (router, client, loginPath, ssoPath, afterLoginPath, groups = true) {
2
4
  router.get(loginPath, (req, res) => {
3
5
  // Set redirectTo
@@ -10,11 +12,13 @@ function login (router, client, loginPath, ssoPath, afterLoginPath, groups = tru
10
12
  scopes.push('groups');
11
13
 
12
14
  // Standard flow initiates directly
13
- res.redirect(client.authorizationUrl({
15
+ res.redirect(`${client.issuer.authorization_endpoint}?${stringify({
16
+ client_id: client.metadata.client_id,
17
+ response_type: 'code',
18
+ scope: scopes.join(' '),
14
19
  redirect_uri: `${req.protocol}://${req.headers.host}${ssoPath}`,
15
- state: redirectTo ? Buffer.from(redirectTo).toString('hex') : undefined,
16
- scope: scopes.join(' ')
17
- }));
20
+ state: redirectTo ? Buffer.from(redirectTo).toString('base64url') : undefined
21
+ })}`);
18
22
  });
19
23
  }
20
24
 
@@ -1,10 +1,6 @@
1
1
  import { postForm } from '@carisls/sso-core';
2
2
 
3
3
  function refreshRequest (router, client, encryptor, accessTokenModule, refreshTokenModule, idTokenModule) {
4
- const clientId = client.metadata.client_id;
5
- const clientSecret = client.metadata.client_secret || undefined;
6
- const url = client.issuer.token_endpoint;
7
-
8
4
  router.all('*', (req, res, next) => {
9
5
  // Check if SSO cookie is there
10
6
  if (req.cookies['x-session']?.length > 36 || req.token || !req.cookies['x-session-sso']) {
@@ -14,9 +10,9 @@ function refreshRequest (router, client, encryptor, accessTokenModule, refreshTo
14
10
 
15
11
  encryptor
16
12
  .decrypt(req.cookies['x-session-sso'])
17
- .then(token => postForm(url, {
18
- client_id: clientId,
19
- client_secret: clientSecret,
13
+ .then(token => postForm(client.issuer.token_endpoint, {
14
+ client_id: client.metadata.client_id,
15
+ client_secret: client.metadata.client_secret,
20
16
  grant_type: 'refresh_token',
21
17
  refresh_token: token
22
18
  }))
@@ -1,6 +1,6 @@
1
1
  import { HttpError } from '@carisls/sso-core';
2
2
 
3
- function sso (router, client, ssoPath, codeRequestModule, accessTokenModule, refreshTokenModule, idTokenModule) {
3
+ function sso (router, ssoPath, codeRequestModule, accessTokenModule, refreshTokenModule, idTokenModule) {
4
4
  router.get(ssoPath, (req, res, next) => {
5
5
  if (!req.query.code) {
6
6
  next(new HttpError(500, req.query.error));
@@ -14,7 +14,7 @@ function sso (router, client, ssoPath, codeRequestModule, accessTokenModule, ref
14
14
  idTokenModule(res, tokens.id_token, req.protocol === 'https')
15
15
  ]))
16
16
  .then(() => {
17
- res.redirect(req.query.state ? Buffer.from(req.query.state, 'hex').toString('utf8') : '/');
17
+ res.redirect(req.query.state ? Buffer.from(req.query.state, 'base64url').toString('utf8') : '/');
18
18
  })
19
19
  .catch((err) => {
20
20
  next(err);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@carisls/sso-standard",
3
- "version": "1.0.6",
3
+ "version": "1.1.0",
4
4
  "description": "A middleware implementing standard flow SSO",
5
5
  "main": "cjs/index.cjs",
6
6
  "module": "esm/index.js",
@@ -25,7 +25,7 @@
25
25
  "author": "Mihovil Strujic <mstrujic@carisls.com>",
26
26
  "license": "MIT",
27
27
  "dependencies": {
28
- "@carisls/sso-core": "1.0.3",
28
+ "@carisls/sso-core": "1.1.1",
29
29
  "cookie-parser": "^1.4.7",
30
30
  "debug": "^4.4.0",
31
31
  "express": "^4.21.2"