Skip to content

Commit 23e4389

Browse files
kanongilMarsup
authored andcommitted
Add a tokenParam option that apply to the /token endpoint
1 parent 62f188b commit 23e4389

File tree

7 files changed

+67
-2
lines changed

7 files changed

+67
-2
lines changed

API.md

+4
Original file line numberDiff line numberDiff line change
@@ -274,6 +274,10 @@ Each strategy accepts the following optional settings:
274274
- `uri` - allows pointing to a private enterprise installation (e.g.
275275
`'https://vpn.example.com'`). See [Providers documentation](https://github.com/hapijs/bell/blob/master/Providers.md) for more
276276
information.
277+
- `tokenParams` - provider-specific query parameters for the token endpoint. It may be
278+
passed either as an object to merge into the query string, or a function which takes the client's
279+
`request` and returns an object. Each provider supports its own set of parameters which customize
280+
the user's login experience.
277281
- `profileParams` - an object of key-value pairs that specify additional URL query parameters to
278282
send with the profile request to the provider. The built-in `facebook` provider, for example,
279283
could have `fields` specified to determine the fields returned from the user's graph, which would

Providers.md

+12-1
Original file line numberDiff line numberDiff line change
@@ -37,12 +37,23 @@ credentials.profile = {
3737

3838
[Provider Documentation](https://auth0.com/docs/protocols#oauth-server-side)
3939

40-
- `scope`: not applicable
40+
- `scope`: Defaults to `['openid', 'email', 'profile']`
4141
- `config`:
4242
- `domain`: Your Auth0 domain name, such as `example.auth0.com` or `example.eu.auth0.com`
4343
- `auth`: [/authorize](https://auth0.com/docs/auth-api#!#get--authorize_social)
4444
- `token`: [/oauth/token](https://auth0.com/docs/protocols#3-getting-the-access-token)
4545

46+
To create a token for a specific endpoint, add it to the `providerParams` and `tokenParams` options, eg.:
47+
48+
```js
49+
providerParams: {
50+
endpoint: 'https://api.service.com'
51+
},
52+
tokenParams: {
53+
endpoint: 'https://api.service.com'
54+
}
55+
```
56+
4657
To authenticate a user with a specific identity provider directly, use `providerParams`. For example:
4758

4859
```javascript

lib/index.d.ts

+6
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,12 @@ export interface OptionalOptions {
125125
| { extendedProfile?: boolean | undefined; getMethod?: string | undefined }
126126
| { uri?: string | undefined }
127127
| undefined;
128+
/**
129+
* provider-specific query parameters for the token endpoint.
130+
* It may be passed either as an object to merge into the query string,
131+
* or a function which takes the client's request and returns an object.
132+
*/
133+
tokenParams?: StringLikeMap | ((request: Request) => StringLikeMap) | undefined;
128134
/**
129135
* an object of key-value pairs that specify additional
130136
* URL query parameters to send with the profile request to the provider.

lib/index.js

+2
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,8 @@ internals.schema = Joi.object({
104104

105105
config: Joi.object(),
106106

107+
tokenParams: Joi.alternatives(Joi.object(), Joi.func()),
108+
107109
profileParams: Joi.object(),
108110

109111
skipProfile: internals.flexBoolean.optional().default(false),

lib/oauth.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -248,7 +248,8 @@ exports.v2 = function (settings) {
248248
const query = {
249249
grant_type: 'authorization_code',
250250
code: request.query.code,
251-
redirect_uri: internals.location(request, protocol, settings.location)
251+
redirect_uri: internals.location(request, protocol, settings.location),
252+
...internals.resolveProviderParams(request, settings.tokenParams)
252253
};
253254

254255
if (settings.provider.pkce) {

test/mock.js

+4
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,10 @@ exports.v2 = async function (flags, options = {}) {
226226
payload.id = 'https://login.salesforce.com/id/foo/bar';
227227
}
228228

229+
if (code.client_id === 'endpoint') {
230+
payload.endpoint = request.payload.endpoint;
231+
}
232+
229233
return h.response(payload).code(options.code ?? 200);
230234
}
231235
}

test/oauth.js

+37
Original file line numberDiff line numberDiff line change
@@ -1270,6 +1270,43 @@ describe('Bell', () => {
12701270
expect(res.headers.location).to.contain(mock.uri + '/auth?special=true&runtime=5&client_id=test&response_type=code&redirect_uri=http%3A%2F%2Flocalhost%3A8080%2Flogin&state=');
12711271
});
12721272

1273+
it('authenticates an endpoint token provider parameters', async (flags) => {
1274+
1275+
const mock = await Mock.v2(flags);
1276+
const server = Hapi.server({ host: 'localhost', port: 8080 });
1277+
await server.register(Bell);
1278+
1279+
server.auth.strategy('custom', 'bell', {
1280+
password: 'cookie_encryption_password_secure',
1281+
isSecure: false,
1282+
clientId: 'endpoint',
1283+
clientSecret: 'secret',
1284+
provider: mock.provider,
1285+
tokenParams: { endpoint: 'https://test.com' }
1286+
});
1287+
1288+
server.route({
1289+
method: '*',
1290+
path: '/login',
1291+
options: {
1292+
auth: 'custom',
1293+
handler: function (request, h) {
1294+
1295+
return request.auth.artifacts;
1296+
}
1297+
}
1298+
});
1299+
1300+
const res1 = await server.inject('/login');
1301+
const cookie = res1.headers['set-cookie'][0].split(';')[0] + ';';
1302+
1303+
const res2 = await mock.server.inject(res1.headers.location);
1304+
1305+
const res3 = await server.inject({ url: res2.headers.location, headers: { cookie } });
1306+
expect(res3.statusCode).to.equal(200);
1307+
expect(res3.result).to.include({ endpoint: 'https://test.com' });
1308+
});
1309+
12731310
it('authenticates an endpoint via oauth with plain PKCE', async (flags) => {
12741311

12751312
const mock = await Mock.v2(flags);

0 commit comments

Comments
 (0)