Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions lib/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ export interface OptionalOptions {
* * Twitter supports `force_login`, `screen_name`.
* * Linkedin supports `fields`.
*/
providerParams?: StringLikeMap | ((request: Request) => StringLikeMap) | undefined;
providerParams?: StringLikeMap | ((request: Request) => StringLikeMap | Promise<StringLikeMap>) | undefined;
/**
* allows passing query parameters from a bell protected endpoint to the auth request.
* It will merge the query params you pass along with the providerParams and any other predefined ones.
Expand Down Expand Up @@ -129,7 +129,7 @@ export interface OptionalOptions {
* It may be passed either as an object to merge into the query string,
* or a function which takes the client's request and returns an object.
*/
tokenParams?: StringLikeMap | ((request: Request) => StringLikeMap) | undefined;
tokenParams?: StringLikeMap | ((request: Request) => StringLikeMap | Promise<StringLikeMap>) | undefined;
/**
* an object of key-value pairs that specify additional
* URL query parameters to send with the profile request to the provider.
Expand Down Expand Up @@ -307,4 +307,4 @@ export function simulate(credentialsFunc: RequestPassThrough): void;
* [See docs](https://github.com/hapijs/bell/blob/master/API.md#simulated-authentication)
* Disables simulation mode
*/
export function simulate(state: false): void;
export function simulate(state: false): void;
10 changes: 5 additions & 5 deletions lib/oauth.js
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ exports.v1 = function (settings) {
h.state(cookie, state);

const authQuery = {
...internals.resolveProviderParams(request, settings.providerParams),
...await internals.resolveProviderParams(request, settings.providerParams),
oauth_token: temp.oauth_token,
...(settings.allowRuntimeProviderParams && request.query)
};
Expand Down Expand Up @@ -178,7 +178,7 @@ exports.v2 = function (settings) {

const nonce = Cryptiles.randomAlphanumString(internals.nonceLength);
const query = {
...internals.resolveProviderParams(request, settings.providerParams),
...await internals.resolveProviderParams(request, settings.providerParams),
...(settings.allowRuntimeProviderParams && request.query),
client_id: settings.clientId,
response_type: 'code',
Expand Down Expand Up @@ -249,7 +249,7 @@ exports.v2 = function (settings) {
grant_type: 'authorization_code',
code: request.query.code,
redirect_uri: internals.location(request, protocol, settings.location),
...internals.resolveProviderParams(request, settings.tokenParams)
...await internals.resolveProviderParams(request, settings.tokenParams)
};

if (settings.provider.pkce) {
Expand Down Expand Up @@ -727,7 +727,7 @@ internals.getProtocol = function (request, settings) {
};


internals.resolveProviderParams = function (request, params) {
internals.resolveProviderParams = async function (request, params) {

return (typeof params === 'function' ? params(request) : params) ?? {};
return (typeof params === 'function' ? await params(request) : params) ?? {};
};
78 changes: 78 additions & 0 deletions test/oauth.js
Original file line number Diff line number Diff line change
Expand Up @@ -1307,6 +1307,84 @@ describe('Bell', () => {
expect(res3.result).to.include({ endpoint: 'https://test.com' });
});

it('authenticates an endpoint token provider parameters as a sync function', async (flags) => {

const mock = await Mock.v2(flags);
const server = Hapi.server({ host: 'localhost', port: 8080 });
await server.register(Bell);

server.auth.strategy('custom', 'bell', {
password: 'cookie_encryption_password_secure',
isSecure: false,
clientId: 'endpoint',
clientSecret: 'secret',
provider: mock.provider,
tokenParams: (_request) => ({ endpoint: 'https://sync.example.com' })
});

server.route({
method: '*',
path: '/login',
options: {
auth: 'custom',
handler: function (request, h) {

return request.auth.artifacts;
}
}
});

const res1 = await server.inject('/login');
const cookie = res1.headers['set-cookie'][0].split(';')[0] + ';';

const res2 = await mock.server.inject(res1.headers.location);

const res3 = await server.inject({ url: res2.headers.location, headers: { cookie } });
expect(res3.statusCode).to.equal(200);
expect(res3.result).to.include({ endpoint: 'https://sync.example.com' });
});

it('authenticates an endpoint token provider parameters as an async function', async (flags) => {

const mock = await Mock.v2(flags);
const server = Hapi.server({ host: 'localhost', port: 8080 });
await server.register(Bell);

server.auth.strategy('custom', 'bell', {
password: 'cookie_encryption_password_secure',
isSecure: false,
clientId: 'endpoint',
clientSecret: 'secret',
provider: mock.provider,
tokenParams: async (_request) => {

await new Promise((resolve) => setTimeout(resolve, 1));
return { endpoint: 'https://async.example.com' };
}
});

server.route({
method: '*',
path: '/login',
options: {
auth: 'custom',
handler: function (request, h) {

return request.auth.artifacts;
}
}
});

const res1 = await server.inject('/login');
const cookie = res1.headers['set-cookie'][0].split(';')[0] + ';';

const res2 = await mock.server.inject(res1.headers.location);

const res3 = await server.inject({ url: res2.headers.location, headers: { cookie } });
expect(res3.statusCode).to.equal(200);
expect(res3.result).to.include({ endpoint: 'https://async.example.com' });
});

it('authenticates an endpoint via oauth with plain PKCE', async (flags) => {

const mock = await Mock.v2(flags);
Expand Down