@carisls/sso-standard 1.0.0 → 1.0.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.
package/cjs/authorize.cjs CHANGED
@@ -62,6 +62,6 @@ function authorize (role, exceptions, redirectToLogin = false) {
62
62
  next();
63
63
  }
64
64
  };
65
- };
65
+ }
66
66
 
67
67
  module.exports = authorize;
package/cjs/index.cjs CHANGED
@@ -24,6 +24,7 @@ const authorize = require('./authorize.cjs');
24
24
  * @param {string} options.paths.afterLogin Change default final endpoint after successful login from /
25
25
  * @param {string} options.paths.logout Change default logout init endpoint from /logout
26
26
  * @param {string} options.paths.afterLogout Change default logout final endpoint after a successful logout from /
27
+ * @param {boolean} options.groups To request groups scope (default is true)
27
28
  * @returns
28
29
  */
29
30
  const router = (options) => {
@@ -31,11 +32,13 @@ const router = (options) => {
31
32
  if (!options)
32
33
  throw Error('You need to set options parameter');
33
34
 
34
- if (!options.ssoUrl && !options.providers)
35
- throw Error('ssoUrl is always required');
35
+ const providers = options.providers?.split ? options.providers.split(',').map(i => ({ ssoUrl: i })) : options.providers;
36
36
 
37
- if (!options.clientId && !options.providers)
38
- throw Error('clientId is required');
37
+ if (!options.providers)
38
+ throw Error('providers is always required');
39
+
40
+ if (!options.clientId || !options.clientSecret)
41
+ throw Error('clientId and clientSecret are required');
39
42
 
40
43
  if (!options.publicKeyCache)
41
44
  options.publicKeyCache = 300;
@@ -46,9 +49,6 @@ const router = (options) => {
46
49
  const router = Router();
47
50
 
48
51
  (async () => {
49
- const providers = options.providers || [];
50
- if (!providers.length && options.ssoUrl)
51
- providers.push({ iss: options.iss || options.ssoUrl, ssoUrl: options.ssoUrl, publicKey: options.publicKey });
52
52
  const issuerSelector = await issuerSelectorModule(providers, options.publicKeyCache);
53
53
  const encryptor = encryptorModule(options.encPassword, options.encPasswordSalt, options.encIterationCount);
54
54
 
@@ -60,9 +60,10 @@ const router = (options) => {
60
60
  encryptor,
61
61
  options.userMapper,
62
62
  options.paths,
63
- options.expOffset);
64
-
65
- })()
63
+ options.expOffset,
64
+ options.groups ?? true
65
+ );
66
+ })()
66
67
  .catch((err) => {
67
68
  router.all('*', (req, res, next) => {
68
69
  next(new HttpError(500, 'SSO settings have failed to load'));
@@ -73,7 +74,7 @@ const router = (options) => {
73
74
  return router;
74
75
  };
75
76
 
76
- module.exports = {
77
+ module.exports = {
77
78
  router,
78
79
  authorize
79
80
  };
@@ -6,6 +6,6 @@ function cookieParser (router) {
6
6
  else
7
7
  cookieParserModule()(req, res, next); // Cookie parser is needed
8
8
  });
9
- };
9
+ }
10
10
 
11
11
  module.exports = cookieParser;
@@ -20,6 +20,6 @@ function logout (router, client, encryptor, logoutPath, afterLogoutPath) {
20
20
 
21
21
  }));
22
22
  });
23
- };
23
+ }
24
24
 
25
25
  module.exports = logout;
@@ -26,6 +26,6 @@ function user (router, encryptor, userMapper) {
26
26
  next();
27
27
  });
28
28
  });
29
- };
29
+ }
30
30
 
31
31
  module.exports = user;
@@ -12,6 +12,6 @@ function codeRequest (client) {
12
12
  code,
13
13
  redirect_uri: redirectUri
14
14
  });
15
- };
15
+ }
16
16
 
17
17
  module.exports = codeRequest;
@@ -13,7 +13,7 @@ const codeRequestModule2 = require('./codeRequest.cjs');
13
13
 
14
14
  const userModule = require('../shared/user.cjs');
15
15
 
16
- function index (router, clientId, clientSecret, issuerSelector, encryptor, userMapper, paths, expOffset = 0) {
16
+ function index (router, clientId, clientSecret, issuerSelector, encryptor, userMapper, paths, expOffset = 0, groups = true) {
17
17
  // Add cookieParser
18
18
  cookieParserModule(router);
19
19
 
@@ -40,7 +40,8 @@ function index (router, clientId, clientSecret, issuerSelector, encryptor, userM
40
40
  client,
41
41
  paths?.login || '/login',
42
42
  paths?.sso || '/sso',
43
- paths?.afterLogin || '/'
43
+ paths?.afterLogin || '/',
44
+ groups ?? true
44
45
  );
45
46
 
46
47
  // Handle return from standard SSO
@@ -69,6 +70,6 @@ function index (router, clientId, clientSecret, issuerSelector, encryptor, userM
69
70
 
70
71
  // Inject user from session cookie if present
71
72
  userModule(router, encryptor, userMapper);
72
- };
73
+ }
73
74
 
74
75
  module.exports = index;
@@ -1,15 +1,21 @@
1
- function login (router, client, loginPath, ssoPath, afterLoginPath) {
1
+ function login (router, client, loginPath, ssoPath, afterLoginPath, groups = true) {
2
2
  router.get(loginPath, (req, res) => {
3
3
  // Set redirectTo
4
4
  const redirectTo = req.query.ReturnUrl || afterLoginPath;
5
5
 
6
+ // Set default scopes
7
+ const scopes = ['openid', 'profile', 'email', 'offline_access'];
8
+
9
+ if (groups === true)
10
+ scopes.push('groups');
11
+
6
12
  // Standard flow initiates directly
7
13
  res.redirect(client.authorizationUrl({
8
14
  redirect_uri: `${req.protocol}://${req.headers.host}${ssoPath}`,
9
15
  state: redirectTo ? Buffer.from(redirectTo).toString('hex') : undefined,
10
- scope: 'openid profile email offline_access groups'
16
+ scope: scopes.join(' ')
11
17
  }));
12
18
  });
13
- };
19
+ }
14
20
 
15
21
  module.exports = login;
@@ -42,6 +42,6 @@ function refreshRequest (router, client, encryptor, accessTokenModule, refreshTo
42
42
  next();
43
43
  });
44
44
  });
45
- };
45
+ }
46
46
 
47
47
  module.exports = refreshRequest;
@@ -20,6 +20,6 @@ function sso (router, client, ssoPath, codeRequestModule, accessTokenModule, ref
20
20
  next(err);
21
21
  });
22
22
  });
23
- };
23
+ }
24
24
 
25
25
  module.exports = sso;
@@ -0,0 +1,17 @@
1
+ import neostandard from 'neostandard';
2
+
3
+ export default [
4
+ ...neostandard({ semi: true }),
5
+ {
6
+ rules: {
7
+ curly: ['error', 'multi-or-nest'],
8
+ '@stylistic/brace-style': ['error', 'stroustrup'],
9
+ 'no-undef': ['warn', { typeof: true }],
10
+ 'no-unused-vars': ['warn']
11
+ }
12
+ },
13
+ {
14
+ files: ['**/*.test.js'],
15
+ rules: { 'no-unused-expressions': 'off' }
16
+ }
17
+ ];
package/esm/authorize.js CHANGED
@@ -62,6 +62,6 @@ function authorize (role, exceptions, redirectToLogin = false) {
62
62
  next();
63
63
  }
64
64
  };
65
- };
65
+ }
66
66
 
67
67
  export default authorize;
package/esm/index.js CHANGED
@@ -25,6 +25,7 @@ import authorize from '../cjs/authorize.cjs';
25
25
  * @param {string} options.paths.logout Change default logout init endpoint from /logout
26
26
  * @param {string} options.paths.afterLogout Change default logout final endpoint after a successful logout from /
27
27
  * @param {boolean} options.useCachedSession Whether or not to store access token to cache instead of a cookie (if larger than 4096)
28
+ * @param {boolean} options.groups To request groups scope (default is true)
28
29
  * @returns
29
30
  */
30
31
  const router = (options) => {
@@ -32,11 +33,13 @@ const router = (options) => {
32
33
  if (!options)
33
34
  throw Error('You need to set options parameter');
34
35
 
35
- if (!options.ssoUrl && !options.providers)
36
- throw Error('ssoUrl is always required');
36
+ const providers = options.providers?.split ? options.providers.split(',').map(i => ({ ssoUrl: i })) : options.providers;
37
37
 
38
- if (!options.clientId && !options.providers)
39
- throw Error('clientId is required');
38
+ if (!options.providers)
39
+ throw Error('providers is always required');
40
+
41
+ if (!options.clientId || !options.clientSecret)
42
+ throw Error('clientId and clientSecret are required');
40
43
 
41
44
  if (!options.publicKeyCache)
42
45
  options.publicKeyCache = 300;
@@ -47,9 +50,6 @@ const router = (options) => {
47
50
  const router = Router();
48
51
 
49
52
  (async () => {
50
- const providers = options.providers || [];
51
- if (!providers.length && options.ssoUrl)
52
- providers.push({ iss: options.iss || options.ssoUrl, ssoUrl: options.ssoUrl, publicKey: options.publicKey });
53
53
  const issuerSelector = await issuerSelectorModule(providers, options.publicKeyCache);
54
54
  const encryptor = encryptorModule(options.encPassword, options.encPasswordSalt, options.encIterationCount);
55
55
 
@@ -61,8 +61,9 @@ const router = (options) => {
61
61
  encryptor,
62
62
  options.userMapper,
63
63
  options.paths,
64
- options.expOffset);
65
-
64
+ options.expOffset,
65
+ options.groups ?? true
66
+ );
66
67
  })()
67
68
  .catch((err) => {
68
69
  router.all('*', (req, res, next) => {
@@ -76,7 +77,7 @@ const router = (options) => {
76
77
 
77
78
  export { router, authorize };
78
79
 
79
- export default {
80
+ export default {
80
81
  router,
81
82
  authorize
82
- }
83
+ };
@@ -6,6 +6,6 @@ function cookieParser (router) {
6
6
  else
7
7
  cookieParserModule()(req, res, next); // Cookie parser is needed
8
8
  });
9
- };
9
+ }
10
10
 
11
11
  export default cookieParser;
@@ -20,6 +20,6 @@ function logout (router, client, encryptor, logoutPath, afterLogoutPath) {
20
20
 
21
21
  }));
22
22
  });
23
- };
23
+ }
24
24
 
25
25
  export default logout;
@@ -26,6 +26,6 @@ function user (router, encryptor, userMapper) {
26
26
  next();
27
27
  });
28
28
  });
29
- };
29
+ }
30
30
 
31
31
  export default user;
@@ -12,6 +12,6 @@ function codeRequest (client) {
12
12
  code,
13
13
  redirect_uri: redirectUri
14
14
  });
15
- };
15
+ }
16
16
 
17
17
  export default codeRequest;
@@ -13,7 +13,7 @@ import codeRequestModule2 from './codeRequest.js';
13
13
 
14
14
  import userModule from '../shared/user.js';
15
15
 
16
- function index (router, clientId, clientSecret, issuerSelector, encryptor, userMapper, paths, expOffset = 0) {
16
+ function index (router, clientId, clientSecret, issuerSelector, encryptor, userMapper, paths, expOffset = 0, groups = true) {
17
17
  // Add cookieParser
18
18
  cookieParserModule(router);
19
19
 
@@ -40,7 +40,8 @@ function index (router, clientId, clientSecret, issuerSelector, encryptor, userM
40
40
  client,
41
41
  paths?.login || '/login',
42
42
  paths?.sso || '/sso',
43
- paths?.afterLogin || '/'
43
+ paths?.afterLogin || '/',
44
+ groups ?? true
44
45
  );
45
46
 
46
47
  // Handle return from standard SSO
@@ -69,6 +70,6 @@ function index (router, clientId, clientSecret, issuerSelector, encryptor, userM
69
70
 
70
71
  // Inject user from session cookie if present
71
72
  userModule(router, encryptor, userMapper);
72
- };
73
+ }
73
74
 
74
75
  export default index;
@@ -1,15 +1,21 @@
1
- function login (router, client, loginPath, ssoPath, afterLoginPath) {
1
+ function login (router, client, loginPath, ssoPath, afterLoginPath, groups = true) {
2
2
  router.get(loginPath, (req, res) => {
3
3
  // Set redirectTo
4
4
  const redirectTo = req.query.ReturnUrl || afterLoginPath;
5
5
 
6
+ // Set default scopes
7
+ const scopes = ['openid', 'profile', 'email', 'offline_access'];
8
+
9
+ if (groups === true)
10
+ scopes.push('groups');
11
+
6
12
  // Standard flow initiates directly
7
13
  res.redirect(client.authorizationUrl({
8
14
  redirect_uri: `${req.protocol}://${req.headers.host}${ssoPath}`,
9
15
  state: redirectTo ? Buffer.from(redirectTo).toString('hex') : undefined,
10
- scope: 'openid profile email offline_access groups'
16
+ scope: scopes.join(' ')
11
17
  }));
12
18
  });
13
- };
19
+ }
14
20
 
15
21
  export default login;
@@ -42,6 +42,6 @@ function refreshRequest (router, client, encryptor, accessTokenModule, refreshTo
42
42
  next();
43
43
  });
44
44
  });
45
- };
45
+ }
46
46
 
47
47
  export default refreshRequest;
@@ -20,6 +20,6 @@ function sso (router, client, ssoPath, codeRequestModule, accessTokenModule, ref
20
20
  next(err);
21
21
  });
22
22
  });
23
- };
23
+ }
24
24
 
25
25
  export default sso;
package/package.json CHANGED
@@ -1,12 +1,20 @@
1
1
  {
2
2
  "name": "@carisls/sso-standard",
3
- "version": "1.0.0",
3
+ "version": "1.0.2",
4
4
  "description": "A middleware implementing standard flow SSO",
5
5
  "main": "cjs/index.cjs",
6
6
  "module": "esm/index.js",
7
7
  "type": "module",
8
+ "exports": {
9
+ ".": {
10
+ "require": "./cjs/index.cjs",
11
+ "import": "./esm/index.js"
12
+ }
13
+ },
8
14
  "scripts": {
9
- "test": "echo \"Error: no test specified\" && exit 1"
15
+ "test": "npm run test:lint",
16
+ "test:lint": "eslint '**/*.js' '**/*.cjs'",
17
+ "test:lint-fix": "eslint '**/*.js' '**/*.cjs' --fix"
10
18
  },
11
19
  "keywords": [
12
20
  "sso",
@@ -17,8 +25,12 @@
17
25
  "author": "Mihovil Strujic <mstrujic@carisls.com>",
18
26
  "license": "MIT",
19
27
  "dependencies": {
20
- "@carisls/sso-core": "^1.0.0",
28
+ "@carisls/sso-core": "file:../core",
21
29
  "cookie-parser": "^1.4.6",
22
30
  "express": "^4.19.2"
31
+ },
32
+ "devDependencies": {
33
+ "eslint": "^9.9.1",
34
+ "neostandard": "^0.11.4"
23
35
  }
24
36
  }