session-sync-auth-site 0.2.0 → 0.3.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.
package/README.md CHANGED
@@ -65,9 +65,18 @@ app.use(authenticate({
65
65
  ```js
66
66
  setUpSessionSyncAuthRoutes({
67
67
  app, // required
68
- siteId, // required
69
- authDomain, // required
70
- jwtSecret, // required
68
+ siteId, // required (unless getSetupInfo provided)
69
+ authDomain, // required (unless getSetupInfo provided)
70
+ jwtSecret, // required (unless getSetupInfo provided)
71
+ getSetupInfo: req => { // useful for multi-tenancy setups
72
+ // fetch the needed values based upon req
73
+ return {
74
+ siteId,
75
+ authDomain,
76
+ jwtSecret,
77
+ extraUserTableValues, // optional
78
+ }
79
+ },
71
80
  protocol: 'https',
72
81
  paths: {
73
82
  getUser: '/get-user',
@@ -93,15 +102,25 @@ setUpSessionSyncAuthRoutes({
93
102
  callbacks: {
94
103
  canceledLogin: ({ origin }) => {},
95
104
  successfulLogin: ({ origin, accessToken }) => {},
105
+ canceledAccountUpdate: ({ origin }) => {},
106
+ successfulAccountUpdate: ({ origin }) => {},
96
107
  successfulLogout: ({ origin }) => {},
97
108
  unnecessaryLogout: ({ origin }) => {},
98
109
  error: ({ errorMessage }) => {},
99
110
  },
111
+ // enabledSSR: true, // Include this if you use server-side-rendering
100
112
  })
101
113
 
102
114
  // To change the default origin...
103
115
  // window.sessionSyncAuth.setDefaultOrigin('https://my-backend-domain.com')
104
116
 
117
+ // When getting data from your backend via AJAX, add in a x-access-token header...
118
+ // const response = await fetch(url, {
119
+ // headers: {
120
+ // 'x-access-token': window.sessionSyncAuth.getAccessToken(),
121
+ // },
122
+ // })
123
+
105
124
  </script>
106
125
  <head>
107
126
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "session-sync-auth-site",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "main": "src/index.js",
5
5
  "repository": {
6
6
  "type": "git",
@@ -26,7 +26,25 @@ const authenticate = ({
26
26
  console.log('...DB connection established for session-sync-auth-site.')
27
27
  }
28
28
 
29
- const accessToken = req.headers['x-access-token'] || req.query.accessToken
29
+ let accessToken = req.headers['x-access-token']
30
+
31
+ if(!accessToken && req.query.accessToken) {
32
+ accessToken = req.query.accessToken
33
+
34
+ // set cookie in case they have enableSSR=true
35
+ let cookieObj = {}
36
+ try {
37
+ cookieObj = JSON.parse(req.cookies.sessionSyncAuthAccessTokenByOrigin)
38
+ } catch(e) {}
39
+ cookieObj[`${req.protocol}://${req.headers.host}`] = accessToken
40
+ res.cookie('sessionSyncAuthAccessTokenByOrigin', JSON.stringify(cookieObj))
41
+ }
42
+
43
+ if(!accessToken) {
44
+ try {
45
+ accessToken = JSON.parse(req.cookies.sessionSyncAuthAccessTokenByOrigin)[`${req.protocol}://${req.headers.host}`]
46
+ } catch(err) {}
47
+ }
30
48
 
31
49
  if(!accessToken) return next()
32
50
 
@@ -55,7 +55,7 @@ const setUpConnection = require('./setUpConnection')
55
55
  console.log(``)
56
56
  console.log(`Tables ${userTableName} and ${sessionTableName} created.`)
57
57
  console.log(``)
58
- console.log(`Note: The user table may be extended with other columns so long as they are nullable.`)
58
+ console.log(`Note: The user table may be extended with other columns so long as they are nullable or provided via extraUserTableValues.`)
59
59
  console.log(``)
60
60
 
61
61
  } catch(err) {
@@ -1,12 +1,36 @@
1
1
  ;(() => {
2
2
 
3
+ let enableSSR = false
3
4
  let defaultOrigin
4
5
  const setDefaultOrigin = origin => {
5
6
  defaultOrigin = origin
6
7
  }
7
8
 
9
+ const getLocalStorageOrCookieItem = item => {
10
+ if(enableSSR) {
11
+ const desiredCookieNameAndValue = (
12
+ document.cookie.split(/; ?/g)
13
+ .map(cookieNameAndValue => cookieNameAndValue.split(/=/g))
14
+ .find(([ cookieName ]) => cookieName === item)
15
+ )
16
+ if(!desiredCookieNameAndValue) return undefined
17
+ return decodeURIComponent(desiredCookieNameAndValue[1])
18
+ } else {
19
+ return localStorage.getItem(item)
20
+ }
21
+ }
22
+
23
+ const setLocalStorageOrCookieItem = (item, value) => {
24
+ if(enableSSR) {
25
+ const expireStr = new Date(Date.now() + (365 * 1000 * 60 * 60 * 24)).toUTCString() // one year
26
+ document.cookie = item + "=" + encodeURIComponent(value) + ";expires=" + expireStr + ";path=/";
27
+ } else {
28
+ localStorage.setItem(item, value)
29
+ }
30
+ }
31
+
8
32
  const getAccessToken = ({ origin=defaultOrigin }={}) => (
9
- JSON.parse(localStorage.getItem('sessionSyncAuthAccessTokenByOrigin') || `{}`)[origin]
33
+ JSON.parse(getLocalStorageOrCookieItem('sessionSyncAuthAccessTokenByOrigin') || `{}`)[origin]
10
34
  )
11
35
 
12
36
  const getQueryStringAddOn = extraQueryParamsForCallbacks => {
@@ -19,15 +43,24 @@
19
43
  return queryStringAddOn
20
44
  }
21
45
 
22
- const logIn = async ({ origin=defaultOrigin, extraQueryParamsForCallbacks }={}) => {
23
- const cancelRedirectUrl = `${location.href.replace(/\?.*$/, '')}?action=canceledLogin&origin=${encodeURIComponent(origin)}${getQueryStringAddOn(extraQueryParamsForCallbacks)}`
24
- const loggedInRedirectUrl = `${location.href.replace(/\?.*$/, '')}?action=successfulLogin&origin=${encodeURIComponent(origin)}&accessToken=ACCESS_TOKEN${getQueryStringAddOn(extraQueryParamsForCallbacks)}`
46
+ const logIn = async ({ origin=defaultOrigin, extraQueryParamsForCallbacks, redirectHref }={}) => {
47
+ const cancelRedirectUrl = `${redirectHref || location.href.replace(/\?.*$/, '')}?action=canceledLogin&origin=${encodeURIComponent(origin)}${getQueryStringAddOn(extraQueryParamsForCallbacks)}`
48
+ const loggedInRedirectUrl = `${redirectHref || location.href.replace(/\?.*$/, '')}?action=successfulLogin&origin=${encodeURIComponent(origin)}&accessToken=ACCESS_TOKEN${getQueryStringAddOn(extraQueryParamsForCallbacks)}`
25
49
 
26
50
  const queryString = `cancelRedirectUrl=${encodeURIComponent(cancelRedirectUrl)}&loggedInRedirectUrl=${encodeURIComponent(loggedInRedirectUrl)}`
27
51
 
28
52
  window.location = `${origin}/log-in?${queryString}`
29
53
  }
30
54
 
55
+ const updateAccount = async ({ origin=defaultOrigin, extraQueryParamsForCallbacks, redirectHref }={}) => {
56
+ const cancelRedirectUrl = `${redirectHref || location.href.replace(/\?.*$/, '')}?action=canceledAccountUpdate&origin=${encodeURIComponent(origin)}${getQueryStringAddOn(extraQueryParamsForCallbacks)}`
57
+ const updatedRedirectUrl = `${redirectHref || location.href.replace(/\?.*$/, '')}?action=successfulAccountUpdate&origin=${encodeURIComponent(origin)}${getQueryStringAddOn(extraQueryParamsForCallbacks)}`
58
+
59
+ const queryString = `cancelRedirectUrl=${encodeURIComponent(cancelRedirectUrl)}&updatedRedirectUrl=${encodeURIComponent(updatedRedirectUrl)}`
60
+
61
+ window.location = `${origin}/update-account?${queryString}`
62
+ }
63
+
31
64
  const getUser = async ({ origin=defaultOrigin }={}) => {
32
65
  const response = await fetch(`${origin}/get-user`, {
33
66
  headers: {
@@ -48,10 +81,14 @@
48
81
  window.location = `${origin}/log-out?${queryString}`
49
82
  }
50
83
 
51
- const init = ({ defaultOrigin, callbacks }) => {
84
+ const init = ({ defaultOrigin, callbacks, enableSSR: newEnableSSRValue }) => {
52
85
 
53
86
  if(defaultOrigin) setDefaultOrigin(defaultOrigin)
54
87
 
88
+ if(typeof newEnableSSRValue === 'boolean') {
89
+ enableSSR = newEnableSSRValue
90
+ }
91
+
55
92
  const getParam = regex => decodeURIComponent((window.location.search.match(regex) || [])[1] || '') || null
56
93
 
57
94
  const origin = getParam(/[?&]origin=([^&]*)/)
@@ -60,13 +97,19 @@
60
97
  const errorMessage = getParam(/[?&]errorMessage=([^&]*)/)
61
98
 
62
99
  if(origin) {
63
- const sessionSyncAuthAccessTokenByOrigin = JSON.parse(localStorage.getItem('sessionSyncAuthAccessTokenByOrigin') || `{}`)
100
+ const sessionSyncAuthAccessTokenByOrigin = JSON.parse(getLocalStorageOrCookieItem('sessionSyncAuthAccessTokenByOrigin') || `{}`)
64
101
  if(accessToken) {
65
102
  sessionSyncAuthAccessTokenByOrigin[origin] = accessToken
66
103
  } else if([ 'successfulLogout', 'unnecessaryLogout' ].includes(action)) {
67
104
  delete sessionSyncAuthAccessTokenByOrigin[origin]
68
105
  }
69
- localStorage.setItem('sessionSyncAuthAccessTokenByOrigin', JSON.stringify(sessionSyncAuthAccessTokenByOrigin))
106
+ setLocalStorageOrCookieItem('sessionSyncAuthAccessTokenByOrigin', JSON.stringify(sessionSyncAuthAccessTokenByOrigin))
107
+
108
+ if(accessToken && enableSSR) {
109
+ // refresh without the origin query param
110
+ window.location = `${location.href.replace(/\?.*$/, '')}${window.location.search.replace(/&?(?:origin)=(?:[^&]*)/g, '').replace(/^\?$/, '')}`
111
+ return
112
+ }
70
113
  }
71
114
 
72
115
  try {
@@ -84,6 +127,7 @@
84
127
  const sessionSyncAuth = {
85
128
  getAccessToken,
86
129
  logIn,
130
+ updateAccount,
87
131
  getUser,
88
132
  logOut,
89
133
  init,
@@ -7,16 +7,20 @@ const setUpSessionSyncAuthRoutes = ({
7
7
  siteId,
8
8
  authDomain,
9
9
  jwtSecret,
10
+ getSetupInfo, // for multi-tenancy setup; sent req and must return the siteId, authDomain, and jwtSecret
10
11
  protocol='https',
11
12
  paths: {
12
13
  getUser='/get-user',
13
14
  logIn='/log-in',
15
+ updateAccount='/update-account',
14
16
  logOut='/log-out',
15
17
  authSync='/auth-sync',
16
18
  }={},
17
19
  languageColType='639-3', // OPTIONS: '639-1', '639-3', 'IETF'
18
20
  }) => {
19
21
 
22
+ getSetupInfo = getSetupInfo || (async () => ({ siteId, jwtSecret, authDomain }))
23
+
20
24
  app.get(getUser, (req, res, next) => {
21
25
  res.json({
22
26
  status: req.user ? 'Logged in' : 'Not logged in',
@@ -24,8 +28,9 @@ const setUpSessionSyncAuthRoutes = ({
24
28
  })
25
29
  })
26
30
 
27
- app.get(logIn, (req, res, next) => {
31
+ app.get(logIn, async (req, res, next) => {
28
32
  const { loggedInRedirectUrl, cancelRedirectUrl } = req.query
33
+ const { siteId, jwtSecret, authDomain } = await getSetupInfo(req)
29
34
 
30
35
  const jwtData = jwt.sign(
31
36
  {
@@ -38,8 +43,24 @@ const setUpSessionSyncAuthRoutes = ({
38
43
  res.redirect(`${protocol}://${authDomain}/login?siteId=${encodeURIComponent(siteId)}&jwtData=${encodeURIComponent(jwtData)}`)
39
44
  })
40
45
 
41
- app.get(logOut, (req, res, next) => {
46
+ app.get(updateAccount, async (req, res, next) => {
47
+ const { updatedRedirectUrl, cancelRedirectUrl } = req.query
48
+ const { siteId, jwtSecret, authDomain } = await getSetupInfo(req)
49
+
50
+ const jwtData = jwt.sign(
51
+ {
52
+ cancelRedirectUrl,
53
+ updatedRedirectUrl,
54
+ },
55
+ jwtSecret,
56
+ )
57
+
58
+ res.redirect(`${protocol}://${authDomain}/account?siteId=${encodeURIComponent(siteId)}&jwtData=${encodeURIComponent(jwtData)}`)
59
+ })
60
+
61
+ app.get(logOut, async (req, res, next) => {
42
62
  const { redirectUrl, noLoginRedirectUrl } = req.query
63
+ const { siteId, jwtSecret, authDomain } = await getSetupInfo(req)
43
64
 
44
65
  if(!req.user) {
45
66
  console.warn(`logout attemped with no login`)
@@ -59,6 +80,7 @@ const setUpSessionSyncAuthRoutes = ({
59
80
 
60
81
  app.post(authSync, async (req, res, next) => {
61
82
  const { payload } = req.body
83
+ const { jwtSecret, extraUserTableValues } = await getSetupInfo(req)
62
84
 
63
85
  try {
64
86
 
@@ -126,7 +148,7 @@ const setUpSessionSyncAuthRoutes = ({
126
148
 
127
149
  variables[`user__${id}`] = getSnakeCaseOfKeys(
128
150
  user,
129
- [ 'id', 'email', 'name', 'image', 'language', 'created_at', 'updated_at' ],
151
+ [ 'id', 'email', 'name', 'image', 'language', 'gender', 'created_at', 'updated_at' ],
130
152
  )
131
153
 
132
154
  if(languageColType !== 'IETF') {
@@ -137,6 +159,13 @@ const setUpSessionSyncAuthRoutes = ({
137
159
  variables[`user__${id}`].language = iso6393To1[variables[`user__${id}`].language] || 'en'
138
160
  }
139
161
 
162
+ if(extraUserTableValues) {
163
+ variables[`user__${id}`] = {
164
+ ...extraUserTableValues,
165
+ ...variables[`user__${id}`],
166
+ }
167
+ }
168
+
140
169
  mapKeys(variables[`user__${id}`], 'user')
141
170
 
142
171
  queries.push(`
package/test/app.html CHANGED
@@ -12,6 +12,8 @@
12
12
  callbacks: {
13
13
  canceledLogin: ({ origin }) => alert(`Canceled login to ${origin}`),
14
14
  successfulLogin: ({ origin }) => alert(`Successful login to ${origin}`),
15
+ canceledAccountUpdate: ({ origin }) => alert(`Canceled login to ${origin}`),
16
+ successfulAccountUpdate: ({ origin }) => alert(`Successful login to ${origin}`),
15
17
  successfulLogout: ({ origin }) => alert(`Successful logout from ${origin}`),
16
18
  unnecessaryLogout: ({ origin }) => alert(`Unnecessary logout from ${origin}`),
17
19
  error: ({ errorMessage }) => alert(`ERROR: ${errorMessage}`),