forked from panva/node-oidc-provider
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathclient_credentials.js
78 lines (61 loc) · 2.38 KB
/
client_credentials.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
import instance from '../../helpers/weak_cache.js';
import { InvalidGrant, InvalidTarget, InvalidScope } from '../../helpers/errors.js';
import dpopValidate from '../../helpers/validate_dpop.js';
import checkResource from '../../shared/check_resource.js';
import epochTime from '../../helpers/epoch_time.js';
export const handler = async function clientCredentialsHandler(ctx, next) {
const { client } = ctx.oidc;
const { ClientCredentials, ReplayDetection } = ctx.oidc.provider;
const {
features: {
mTLS: { getCertificate },
},
scopes: statics,
} = instance(ctx.oidc.provider).configuration();
const dPoP = await dpopValidate(ctx);
await checkResource(ctx, () => {});
const scopes = ctx.oidc.params.scope ? [...new Set(ctx.oidc.params.scope.split(' '))] : [];
if (client.scope) {
const allowList = new Set(client.scope.split(' '));
for (const scope of scopes.filter(Set.prototype.has.bind(statics))) {
if (!allowList.has(scope)) {
throw new InvalidScope('requested scope is not allowed', scope);
}
}
}
const token = new ClientCredentials({
client,
scope: scopes.join(' ') || undefined,
});
Object.values(ctx.oidc.resourceServers).forEach((resourceServer, i) => {
if (i !== 0) {
throw new InvalidTarget('only a single resource indicator value is supported for this grant type');
}
token.resourceServer = resourceServer;
token.scope = scopes.filter(Set.prototype.has.bind(new Set(resourceServer.scope.split(' ')))).join(' ') || undefined;
});
if (client.tlsClientCertificateBoundAccessTokens) {
const cert = getCertificate(ctx);
if (!cert) {
throw new InvalidGrant('mutual TLS client certificate not provided');
}
token.setThumbprint('x5t', cert);
}
if (dPoP) {
const unique = await ReplayDetection.unique(client.clientId, dPoP.jti, epochTime() + 300);
ctx.assert(unique, new InvalidGrant('DPoP proof JWT Replay detected'));
token.setThumbprint('jkt', dPoP.thumbprint);
} else if (ctx.oidc.client.dpopBoundAccessTokens) {
throw new InvalidGrant('DPoP proof JWT not provided');
}
ctx.oidc.entity('ClientCredentials', token);
const value = await token.save();
ctx.body = {
access_token: value,
expires_in: token.expiration,
token_type: token.tokenType,
scope: token.scope,
};
await next();
};
export const parameters = new Set(['scope']);