mirror of https://github.com/boxyhq/jackson.git
Ability to opt out of sending profile scope (#2436)
* Default should be true, opt-in via JacksonOption * Add new env to example file * Omit profile scope if opted out * Type update * Service env processing * Sync package locks * Add unit tests
This commit is contained in:
parent
3e37a69bf9
commit
92d4f864ce
|
@ -105,3 +105,6 @@ SETUP_LINK_EXPIRY_DAYS=3
|
|||
# Ory integration. You need BOXYHQ_LICENSE_KEY to be set to use this.
|
||||
ENTERPRISE_ORY_SDK_TOKEN=
|
||||
ENTERPRISE_ORY_PROJECT_ID=
|
||||
|
||||
# Uncomment below if you wish to opt-out of sending `profile` scope in OIDC Provider Authorization Request
|
||||
#OIDC_REQUEST_PROFILE_SCOPE=false
|
File diff suppressed because it is too large
Load Diff
|
@ -71,6 +71,7 @@ const jacksonOptions: JacksonOption = {
|
|||
private: process.env.OPENID_RSA_PRIVATE_KEY || '',
|
||||
public: process.env.OPENID_RSA_PUBLIC_KEY || '',
|
||||
},
|
||||
requestProfileScope: process.env.OIDC_REQUEST_PROFILE_SCOPE === 'false' ? false : true,
|
||||
},
|
||||
certs: {
|
||||
publicKey: process.env.PUBLIC_KEY || '',
|
||||
|
|
|
@ -407,8 +407,11 @@ export class OAuthController implements IOAuthController {
|
|||
oidcCodeVerifier = generators.codeVerifier();
|
||||
const code_challenge = generators.codeChallenge(oidcCodeVerifier);
|
||||
oidcNonce = generators.nonce();
|
||||
const standardScopes = this.opts.openid?.requestProfileScope
|
||||
? ['openid', 'email', 'profile']
|
||||
: ['openid', 'email'];
|
||||
ssoUrl = oidcClient.authorizationUrl({
|
||||
scope: [...requestedScopes, 'openid', 'email', 'profile']
|
||||
scope: [...requestedScopes, ...standardScopes]
|
||||
.filter((value, index, self) => self.indexOf(value) === index) // filter out duplicates
|
||||
.join(' '),
|
||||
code_challenge,
|
||||
|
|
|
@ -51,6 +51,7 @@ const defaultOpts = (opts: JacksonOption): JacksonOption => {
|
|||
|
||||
newOpts.openid = newOpts.openid || {};
|
||||
newOpts.openid.jwsAlg = newOpts.openid.jwsAlg || 'RS256';
|
||||
newOpts.openid.requestProfileScope = newOpts.openid?.requestProfileScope ?? true;
|
||||
|
||||
newOpts.boxyhqLicenseKey = newOpts.boxyhqLicenseKey || undefined;
|
||||
|
||||
|
|
|
@ -437,6 +437,7 @@ export interface JacksonOption {
|
|||
private: string;
|
||||
public: string;
|
||||
};
|
||||
requestProfileScope?: boolean; // defaults to true
|
||||
};
|
||||
certs?: {
|
||||
publicKey: string;
|
||||
|
|
|
@ -45,6 +45,38 @@ tap.test('[OIDCProvider]', async (t) => {
|
|||
context.state = params.get('state');
|
||||
});
|
||||
|
||||
t.test('[authorize] Should omit profile scope if openid.requestProfileScope is set to false', async (t) => {
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
oauthController.opts.openid.requestProfileScope = false;
|
||||
const response = (await oauthController.authorize(<OAuthReq>authz_request_oidc_provider)) as {
|
||||
redirect_url: string;
|
||||
};
|
||||
const params = new URLSearchParams(new URL(response.redirect_url!).search);
|
||||
t.ok('redirect_url' in response, 'got the Idp authorize URL');
|
||||
t.ok(params.has('state'), 'state present');
|
||||
t.match(params.get('scope')?.includes('profile'), false, 'profile scope should be absent');
|
||||
});
|
||||
|
||||
t.test(
|
||||
'[authorize] Should include profile scope if openid.requestProfileScope is set to false but request contains scope param',
|
||||
async (t) => {
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
oauthController.opts.openid.requestProfileScope = false;
|
||||
const response = (await oauthController.authorize(<OAuthReq>{
|
||||
...authz_request_oidc_provider,
|
||||
scope: 'openid email profile',
|
||||
})) as {
|
||||
redirect_url: string;
|
||||
};
|
||||
const params = new URLSearchParams(new URL(response.redirect_url!).search);
|
||||
t.ok('redirect_url' in response, 'got the Idp authorize URL');
|
||||
t.ok(params.has('state'), 'state present');
|
||||
t.match(params.get('scope')?.includes('profile'), true, 'profile scope should be absent');
|
||||
}
|
||||
);
|
||||
|
||||
t.test('[authorize] Should return error if `oidcPath` is not set', async (t) => {
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
|
|
|
@ -85,7 +85,7 @@
|
|||
"@types/node": "20.11.26",
|
||||
"@types/react": "18.2.65",
|
||||
"@typescript-eslint/eslint-plugin": "7.2.0",
|
||||
"@typescript-eslint/parser": "7.1.1",
|
||||
"@typescript-eslint/parser": "7.2.0",
|
||||
"@vitejs/plugin-react": "4.2.1",
|
||||
"eslint": "8.57.0",
|
||||
"eslint-plugin-react-hooks": "4.6.0",
|
||||
|
@ -178,6 +178,34 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"internal-ui/node_modules/@typescript-eslint/parser": {
|
||||
"version": "7.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.2.0.tgz",
|
||||
"integrity": "sha512-5FKsVcHTk6TafQKQbuIVkXq58Fnbkd2wDL4LB7AURN7RUOu1utVP+G8+6u3ZhEroW3DF6hyo3ZEXxgKgp4KeCg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@typescript-eslint/scope-manager": "7.2.0",
|
||||
"@typescript-eslint/types": "7.2.0",
|
||||
"@typescript-eslint/typescript-estree": "7.2.0",
|
||||
"@typescript-eslint/visitor-keys": "7.2.0",
|
||||
"debug": "^4.3.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^16.0.0 || >=18.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/typescript-eslint"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"eslint": "^8.56.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"typescript": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"internal-ui/node_modules/typescript": {
|
||||
"version": "5.4.2",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.2.tgz",
|
||||
|
|
Loading…
Reference in New Issue