Skip to content

Commit 176c6bc

Browse files
authored
Add support for multiple issuers (OIDC providers with different JWKS URIs) on a single endpoint (#14)
* add `multiIssuerBearerTokenMiddleware` and `verifyMultiIssuer` * update all packages, apply latest ts-toolkit * move @makerx/node-common to dev deps, since we're only using referencing the type
1 parent 4beb0a8 commit 176c6bc

17 files changed

+5398
-10205
lines changed

.eslintignore

Lines changed: 0 additions & 7 deletions
This file was deleted.

.eslintrc.js

Lines changed: 0 additions & 34 deletions
This file was deleted.

.gitignore

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ logs
44
npm-debug.log*
55
yarn-debug.log*
66
yarn-error.log*
7+
pnpm-debug.log*
78
lerna-debug.log*
89

910
# Dependency directories
@@ -21,8 +22,18 @@ node_modules/
2122
# Stores VSCode versions used for testing VSCode extensions
2223
.vscode-test
2324

25+
# Editor/OS directories and files
26+
.DS_Store
27+
*.suo
28+
2429
# Jetbrains
25-
.idea
30+
.idea/shelf/
31+
.idea/workspace.xml
32+
# Editor-based HTTP Client requests
33+
.idea/httpRequests/
34+
# Datasource local storage ignored files
35+
.idea/dataSources/
36+
.idea/dataSources.local.xml
2637

2738
# yarn v2
2839
.yarn/cache
@@ -33,10 +44,21 @@ node_modules/
3344

3445
# Compiled code
3546
dist/
47+
build/
3648

3749
# Coverage report
3850
coverage
3951

52+
# Test results
53+
test-results.xml
54+
4055
# Website & Code docs generation
4156
code-docs/
4257
out/
58+
59+
# dotenv environment variable files
60+
.env
61+
.env.development.local
62+
.env.test.local
63+
.env.production.local
64+
.env.local

.nsprc

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,2 @@
11
{
2-
"1092330": {
3-
"active": true,
4-
"notes": "The latest version of word-wrap was published 6 years ago",
5-
"expiry": "2023-11-01"
6-
}
7-
}
2+
}

.prettierrc

Lines changed: 0 additions & 7 deletions
This file was deleted.

.prettierrc.cjs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
module.exports = {
2+
...require('@makerx/prettier-config'),
3+
}

.tstoolkitrc.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import type { TsToolkitConfig } from "@makerx/ts-toolkit";
2+
3+
const config: TsToolkitConfig = {
4+
packageConfig: {
5+
srcDir: 'src',
6+
outDir: 'dist',
7+
moduleType: 'commonjs',
8+
main: 'index.ts',
9+
}
10+
}
11+
export default config

.vscode/settings.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,6 @@
22
"editor.formatOnSave": true,
33
"editor.defaultFormatter": "esbenp.prettier-vscode",
44
"editor.codeActionsOnSave": {
5-
"source.fixAll.eslint": true
5+
"source.fixAll.eslint": "explicit"
66
}
7-
}
7+
}

README.md

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,39 @@ To specify per-host config, provide a \*`BearerConfigCallback` in the form of `(
6868

6969
Note: the callback will only be called once per host (config is cached).
7070

71+
### Apps accepting bearer tokens from multiple issuers
72+
73+
If your app needs to accept bearer tokens from multiple issuers (OIDC endpoints) **each with different JWKS URIs** on a single endpoint (not varied by host), `multiIssuerBearerTokenMiddleware` supports this with a different approach. It will:
74+
75+
- decode the token without verifying it
76+
- use the `iss` claim to access the issuer-specific config `IssuerOptions` (or return unauthorized, if not found)
77+
- verify the token using the issuer-specific config (caching JwksClient instances per JWKS URI)
78+
79+
#### Multi-issuer options
80+
81+
```ts
82+
import { IssuerOptions, multiIssuerBearerTokenMiddleware, MultiIssuerBearerAuthOptions } from '@makerxstudio/express-bearer'
83+
84+
const app = express()
85+
const issuerOptions: Record<string, IssuerOptions> = {
86+
'https://example.com/oidc': {
87+
jwksUri: 'https://example.com/oidc/jwks',
88+
verifyOptions: {
89+
audience: 'https://api.example.com',
90+
},
91+
},
92+
'https://login.microsoftonline.com/<tenant ID>/v2.0': {
93+
jwksUri: 'https://login.microsoftonline.com/<tenant ID>/discovery/v2.0/keys',
94+
verifyOptions: {
95+
audience: '<audience ID>',
96+
},
97+
},
98+
}
99+
100+
// add the multi issuer bearer token middleware (to all routes)
101+
app.use(multiIssuerBearerTokenMiddleware({ issuerOptions, tokenIsRequired: true }))
102+
```
103+
71104
## Logging
72105

73106
Set the logger implementation to an object that fulfills the `Logger` definition:

eslint.config.mjs

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import globals from "globals";
2+
import path from "node:path";
3+
import { fileURLToPath } from "node:url";
4+
import js from "@eslint/js";
5+
import { FlatCompat } from "@eslint/eslintrc";
6+
7+
const __filename = fileURLToPath(import.meta.url);
8+
const __dirname = path.dirname(__filename);
9+
const compat = new FlatCompat({
10+
baseDirectory: __dirname,
11+
recommendedConfig: js.configs.recommended,
12+
allConfig: js.configs.all
13+
});
14+
15+
export default [{
16+
ignores: [
17+
"**/.eslintrc.js",
18+
"**/node_modules",
19+
"**/dist",
20+
"**/build",
21+
"**/coverage",
22+
"**/generated/types.d.ts",
23+
"**/generated/types.ts",
24+
"**/.idea",
25+
"**/.vscode",
26+
],
27+
}, ...compat.extends("@makerx/eslint-config"), {
28+
languageOptions: {
29+
globals: {
30+
...globals.node,
31+
},
32+
},
33+
}];

0 commit comments

Comments
 (0)