@wbce-d9/api 12.0.0 → 12.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.
@@ -76,6 +76,14 @@ export class OpenIDAuthDriver extends BaseOAuthDriver {
76
76
  const client = await this.client;
77
77
  const codeChallenge = generators.codeChallenge(codeVerifier);
78
78
  const paramsConfig = typeof this.config['params'] === 'object' ? this.config['params'] : {};
79
+ const redirectAfterLogin = additionalParams?.['redirect'];
80
+ delete additionalParams?.['redirect'];
81
+ let finalRedirectUri = this.redirectUrl;
82
+ if (redirectAfterLogin) {
83
+ const redirectUriWithParams = new URL(this.redirectUrl);
84
+ redirectUriWithParams.searchParams.set('redirect', redirectAfterLogin);
85
+ finalRedirectUri = redirectUriWithParams.toString();
86
+ }
79
87
  return client.authorizationUrl({
80
88
  scope: this.config['scope'] ?? 'openid profile email',
81
89
  access_type: 'offline',
@@ -86,6 +94,7 @@ export class OpenIDAuthDriver extends BaseOAuthDriver {
86
94
  // Some providers require state even with PKCE
87
95
  state: codeChallenge,
88
96
  nonce: codeChallenge,
97
+ redirect_uri: finalRedirectUri,
89
98
  ...additionalParams,
90
99
  });
91
100
  }
@@ -99,7 +108,13 @@ export class OpenIDAuthDriver extends BaseOAuthDriver {
99
108
  try {
100
109
  const client = await this.client;
101
110
  const codeChallenge = generators.codeChallenge(payload['codeVerifier']);
102
- tokenSet = await client.callback(this.redirectUrl, { code: payload['code'], state: payload['state'], iss: payload['iss'] }, { code_verifier: payload['codeVerifier'], state: codeChallenge, nonce: codeChallenge });
111
+ let finalRedirectUri = this.redirectUrl;
112
+ if (payload['redirect']) {
113
+ const redirectUriWithParams = new URL(this.redirectUrl);
114
+ redirectUriWithParams.searchParams.set('redirect', payload['redirect']);
115
+ finalRedirectUri = redirectUriWithParams.toString();
116
+ }
117
+ tokenSet = await client.callback(finalRedirectUri, { code: payload['code'], state: payload['state'], iss: payload['iss'] }, { code_verifier: payload['codeVerifier'], state: codeChallenge, nonce: codeChallenge });
103
118
  userInfo = tokenSet.claims();
104
119
  if (client.issuer.metadata['userinfo_endpoint']) {
105
120
  userInfo = {
@@ -147,28 +162,40 @@ export function createOpenIDAuthRouter(providerName) {
147
162
  expiresIn: '5m',
148
163
  issuer: 'directus',
149
164
  });
150
- res.cookie(`openid.${providerName}`, token, {
165
+ const additionalParams = { ...req.query };
166
+ delete additionalParams['prompt'];
167
+ const authUrl = await provider.generateAuthUrl(codeVerifier, prompt, additionalParams);
168
+ const urlParams = new URL(authUrl);
169
+ const state = urlParams.searchParams.get('state');
170
+ const cookieName = `openid.${providerName}.${state || ''}`;
171
+ res.cookie(cookieName, token, {
151
172
  httpOnly: true,
152
173
  sameSite: 'lax',
153
174
  });
154
- const additionalParams = { ...req.query };
155
- delete additionalParams['prompt'];
156
- delete additionalParams['redirect'];
157
- return res.redirect(await provider.generateAuthUrl(codeVerifier, prompt, additionalParams));
175
+ return res.redirect(authUrl);
158
176
  }), respond);
159
177
  router.post('/callback', express.urlencoded({ extended: false }), (req, res) => {
160
178
  res.redirect(303, `./callback?${new URLSearchParams(req.body)}`);
161
179
  }, respond);
162
180
  router.get('/callback', asyncHandler(async (req, res, next) => {
181
+ const redirectUrl = req.query['redirect'];
182
+ const validRedirectUrl = isRedirectAllowedOnLogin(redirectUrl, providerName) ? redirectUrl : null;
183
+ const state = req.query['state'];
184
+ const cookieName = `openid.${providerName}.${state || ''}`;
185
+ const cookieValue = req.cookies[cookieName];
163
186
  let tokenData;
164
187
  try {
165
- tokenData = jwt.verify(req.cookies[`openid.${providerName}`], env['SECRET'], {
188
+ tokenData = jwt.verify(cookieValue, env['SECRET'], {
166
189
  issuer: 'directus',
167
190
  });
168
191
  }
169
192
  catch (e) {
170
- logger.warn(e, `[OpenID] Couldn't verify OpenID cookie`);
171
- throw new InvalidCredentialsException();
193
+ logger.warn(e, `[OpenID] Couldn't verify OpenID cookie ${state ? `for state ${state}` : ''}`);
194
+ const baseUrl = env['PUBLIC_URL'];
195
+ const loginPath = '/admin/login';
196
+ const url = new URL(loginPath, baseUrl);
197
+ const redirectTo = validRedirectUrl || url.toString();
198
+ return res.redirect(`${redirectTo}?reason=INVALID_CREDENTIALS`);
172
199
  }
173
200
  const { verifier, redirect, prompt } = tokenData;
174
201
  const accountability = {
@@ -187,12 +214,13 @@ export function createOpenIDAuthRouter(providerName) {
187
214
  });
188
215
  let authResponse;
189
216
  try {
190
- res.clearCookie(`openid.${providerName}`);
217
+ res.clearCookie(cookieName);
191
218
  authResponse = await authenticationService.login(providerName, {
192
219
  code: req.query['code'],
193
220
  codeVerifier: verifier,
194
221
  state: req.query['state'],
195
222
  iss: req.query['iss'],
223
+ redirect: validRedirectUrl,
196
224
  });
197
225
  }
198
226
  catch (error) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wbce-d9/api",
3
- "version": "12.0.0",
3
+ "version": "12.0.2",
4
4
  "description": "Directus is a real-time API and App dashboard for managing SQL database content",
5
5
  "type": "module",
6
6
  "keywords": [
@@ -103,7 +103,7 @@
103
103
  "ioredis": "5.3.2",
104
104
  "isolated-vm": "^6.0.1",
105
105
  "joi": "17.9.1",
106
- "js-yaml": "4.1.0",
106
+ "js-yaml": "4.1.1",
107
107
  "js2xmlparser": "5.0.0",
108
108
  "json2csv": "5.0.7",
109
109
  "jsonwebtoken": "9.0.0",
@@ -143,20 +143,20 @@
143
143
  "uuid": "9.0.0",
144
144
  "uuid-validate": "0.0.3",
145
145
  "wellknown": "0.5.0",
146
+ "@wbce-d9/app": "9.33.8",
146
147
  "@wbce-d9/exceptions": "10.0.0",
147
- "@wbce-d9/extensions-sdk": "10.0.0",
148
148
  "@wbce-d9/constants": "10.0.0",
149
- "@wbce-d9/specs": "9.26.5",
150
149
  "@wbce-d9/schema": "10.0.0",
150
+ "@wbce-d9/specs": "9.26.5",
151
151
  "@wbce-d9/storage-driver-azure": "10.0.0",
152
152
  "@wbce-d9/storage": "10.0.0",
153
- "@wbce-d9/storage-driver-cloudinary": "10.0.0",
154
- "@wbce-d9/app": "9.33.7",
153
+ "@wbce-d9/extensions-sdk": "10.0.0",
155
154
  "@wbce-d9/storage-driver-gcs": "10.0.0",
156
- "@wbce-d9/storage-driver-local": "10.0.0",
155
+ "@wbce-d9/storage-driver-cloudinary": "10.0.0",
157
156
  "@wbce-d9/storage-driver-s3": "10.0.0",
158
- "@wbce-d9/update-check": "10.0.0",
159
- "@wbce-d9/utils": "10.0.0"
157
+ "@wbce-d9/storage-driver-local": "10.0.0",
158
+ "@wbce-d9/utils": "10.0.0",
159
+ "@wbce-d9/update-check": "10.0.0"
160
160
  },
161
161
  "devDependencies": {
162
162
  "@ngneat/falso": "6.4.0",