Skip to content

Commit

Permalink
Add option to skip nonce in auth code request
Browse files Browse the repository at this point in the history
  • Loading branch information
nirinchev committed Nov 18, 2024
1 parent 32681c4 commit da87441
Show file tree
Hide file tree
Showing 3 changed files with 78 additions and 35 deletions.
8 changes: 8 additions & 0 deletions src/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,14 @@ export interface MongoDBOIDCPluginOptions {
* broken identity providers.
*/
passIdTokenAsAccessToken?: boolean;

/**
* Skip the nonce parameter in the Authorization Code request. This could
* be used to work with providers that don't support the nonce parameter.
*
* Default is `false`.
*/
skipNonceInAuthCodeRequest?: boolean;
}

/** @public */
Expand Down
101 changes: 67 additions & 34 deletions src/plugin.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,19 @@ async function delay(ms: number) {
return await new Promise((resolve) => setTimeout(resolve, ms));
}

function testAuthCodeFlow(
fn: (opts: Partial<MongoDBOIDCPluginOptions>) => Mocha.Func
): void {
for (let skipNonceInAuthCodeRequest of [true, false]) {

Check failure on line 83 in src/plugin.spec.ts

View workflow job for this annotation

GitHub Actions / Check (ubuntu-latest, 18.x)

'skipNonceInAuthCodeRequest' is never reassigned. Use 'const' instead
describe(`with skipNonceInAuthCodeRequest: ${skipNonceInAuthCodeRequest}`, function () {

Check failure on line 84 in src/plugin.spec.ts

View workflow job for this annotation

GitHub Actions / Check (ubuntu-latest, 18.x)

Invalid type "boolean" of template literal expression
it(
'can successfully authenticate with auth code flow',
fn({ skipNonceInAuthCodeRequest })
);
});
}
}

describe('OIDC plugin (local OIDC provider)', function () {
this.timeout(90_000);

Expand Down Expand Up @@ -138,18 +151,30 @@ describe('OIDC plugin (local OIDC provider)', function () {
plugin = createMongoDBOIDCPlugin(pluginOptions);
});

it('can request tokens through the browser', async function () {
const result = await requestToken(
plugin,
provider.getMongodbOIDCDBInfo()
);
const accessTokenContents = getJWTContents(result.accessToken);
expect(accessTokenContents.sub).to.equal('testuser');
expect(accessTokenContents.client_id).to.equal(
provider.getMongodbOIDCDBInfo().clientId
);
verifySuccessfulAuthCodeFlowLog(await readLog());
});
testAuthCodeFlow(
(opts) =>
async function () {
pluginOptions = {
...pluginOptions,
...opts,
};
plugin = createMongoDBOIDCPlugin(pluginOptions);

const result = await requestToken(
plugin,
provider.getMongodbOIDCDBInfo()
);
const accessTokenContents = getJWTContents(result.accessToken);
expect(accessTokenContents.sub).to.equal('testuser');
expect(accessTokenContents.client_id).to.equal(
provider.getMongodbOIDCDBInfo().clientId
);

const log = await readLog();
console.log(log);

Check failure on line 174 in src/plugin.spec.ts

View workflow job for this annotation

GitHub Actions / Check (ubuntu-latest, 18.x)

Unexpected console statement
verifySuccessfulAuthCodeFlowLog(log);
}
);

it('will re-use tokens while they are valid if no username was provided', async function () {
const skipAuthAttemptEvent = once(
Expand Down Expand Up @@ -1017,18 +1042,22 @@ describe('OIDC plugin (local OIDC provider)', function () {
};
});

it('can successfully authenticate with Okta using auth code flow', async function () {
plugin = createMongoDBOIDCPlugin({
...defaultOpts,
allowedFlows: ['auth-code'],
openBrowser: (opts) =>
oktaBrowserAuthCodeFlow({ ...opts, username, password }),
});
const result = await requestToken(plugin, metadata);
testAuthCodeFlow(
(opts) =>
async function () {
plugin = createMongoDBOIDCPlugin({
...defaultOpts,
allowedFlows: ['auth-code'],
openBrowser: (opts) =>
oktaBrowserAuthCodeFlow({ ...opts, username, password }),
...opts,
});
const result = await requestToken(plugin, metadata);

validateToken(getJWTContents(result.accessToken));
verifySuccessfulAuthCodeFlowLog(await readLog());
});
validateToken(getJWTContents(result.accessToken));
verifySuccessfulAuthCodeFlowLog(await readLog());
}
);

it('can successfully authenticate with Okta using device auth flow', async function () {
plugin = createMongoDBOIDCPlugin({
Expand Down Expand Up @@ -1087,18 +1116,22 @@ describe('OIDC plugin (local OIDC provider)', function () {
};
});

it('can successfully authenticate with Azure using auth code flow', async function () {
plugin = createMongoDBOIDCPlugin({
...defaultOpts,
allowedFlows: ['auth-code'],
openBrowser: (opts) =>
azureBrowserAuthCodeFlow({ ...opts, username, password }),
});
const result = await requestToken(plugin, metadata);
testAuthCodeFlow(
(opts) =>
async function () {
plugin = createMongoDBOIDCPlugin({
...defaultOpts,
allowedFlows: ['auth-code'],
openBrowser: (opts) =>
azureBrowserAuthCodeFlow({ ...opts, username, password }),
...opts,
});
const result = await requestToken(plugin, metadata);

validateToken(getJWTContents(result.accessToken));
verifySuccessfulAuthCodeFlowLog(await readLog());
});
validateToken(getJWTContents(result.accessToken));
verifySuccessfulAuthCodeFlowLog(await readLog());
}
);

it('can successfully authenticate with Azure using device auth flow', async function () {
plugin = createMongoDBOIDCPlugin({
Expand Down
4 changes: 3 additions & 1 deletion src/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -657,7 +657,9 @@ export class MongoDBOIDCPluginImpl implements MongoDBOIDCPlugin {
let client!: BaseClient;
let actualRedirectURI!: string;

const nonce = generators.nonce();
const nonce = this.options.skipNonceInAuthCodeRequest
? undefined
: generators.nonce();

try {
await withAbortCheck(signal, async ({ signalCheck, signalPromise }) => {
Expand Down

0 comments on commit da87441

Please sign in to comment.