@cheellipadi/mock-oidc-provider 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +69 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +54 -0
- package/dist/cli.js.map +1 -0
- package/dist/config.d.ts +13 -0
- package/dist/config.js +149 -0
- package/dist/config.js.map +1 -0
- package/dist/provider.d.ts +10 -0
- package/dist/provider.js +21 -0
- package/dist/provider.js.map +1 -0
- package/package.json +41 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# mock-oidc-provider
|
|
2
|
+
|
|
3
|
+
Generic local OIDC provider for development and testing.
|
|
4
|
+
|
|
5
|
+
This is a proof-of-concept package. It is intended to let local applications exercise
|
|
6
|
+
their normal OIDC authorization-code callback flow without depending on a real
|
|
7
|
+
identity provider account.
|
|
8
|
+
|
|
9
|
+
It is not a production identity provider and must not be deployed as one.
|
|
10
|
+
|
|
11
|
+
## Usage
|
|
12
|
+
|
|
13
|
+
Run the provider from npm in one terminal:
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
pnpm dlx mock-oidc-provider --claim preferred_username=test.user --claim name="Test User"
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
Or, after installing the package, run the binary directly:
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
mock-oidc-provider --claim preferred_username=test.user --claim name="Test User"
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Run the client application in another terminal.
|
|
26
|
+
|
|
27
|
+
By default the provider uses:
|
|
28
|
+
|
|
29
|
+
```text
|
|
30
|
+
host: 127.0.0.1
|
|
31
|
+
port: 4010
|
|
32
|
+
issuer: http://localhost:4010/mock/v2.0
|
|
33
|
+
clientId: mock-oidc-client
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
The provider prints copy-pasteable client application configuration on startup.
|
|
37
|
+
|
|
38
|
+
## Options
|
|
39
|
+
|
|
40
|
+
```text
|
|
41
|
+
--host <host> Bind host. Default: 127.0.0.1
|
|
42
|
+
--port <port> Bind port. Default: 4010
|
|
43
|
+
--issuer <url> Issuer URL. Default: http://localhost:<port>/mock/v2.0
|
|
44
|
+
--client-id <id> Client ID. Default: mock-oidc-client
|
|
45
|
+
--redirect-uri <uri> Additional allowed localhost redirect URI.
|
|
46
|
+
--claim <key=value> Add or override an ID token claim. Repeatable.
|
|
47
|
+
-h, --help Show help.
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
The authorization code flow also supports optional PKCE with
|
|
51
|
+
`code_challenge_method=S256`. Non-PKCE local clients continue to work.
|
|
52
|
+
|
|
53
|
+
## Local package testing
|
|
54
|
+
|
|
55
|
+
Prefer the tarball flow before publishing. It best matches how consumers will run the package:
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
pnpm build
|
|
59
|
+
pnpm pack
|
|
60
|
+
pnpm dlx "$(pwd)/mock-oidc-provider-0.1.0.tgz" --claim preferred_username=test.user
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## Safety defaults
|
|
64
|
+
|
|
65
|
+
- Runs in the foreground.
|
|
66
|
+
- Allows only localhost or 127.0.0.1 redirect URIs.
|
|
67
|
+
- Uses fake local issuer and client defaults.
|
|
68
|
+
- Does not set cookies or sessions in consuming applications.
|
|
69
|
+
- Does not store or dictate where client applications store tokens.
|
package/dist/cli.d.ts
ADDED
package/dist/cli.js
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { getHelpText, HelpRequested, parseArgs } from './config.js';
|
|
3
|
+
import { createProvider } from './provider.js';
|
|
4
|
+
async function main() {
|
|
5
|
+
let config;
|
|
6
|
+
try {
|
|
7
|
+
config = parseArgs(process.argv.slice(2));
|
|
8
|
+
}
|
|
9
|
+
catch (error) {
|
|
10
|
+
if (error instanceof HelpRequested) {
|
|
11
|
+
console.log(getHelpText());
|
|
12
|
+
return;
|
|
13
|
+
}
|
|
14
|
+
console.error(error instanceof Error ? error.message : error);
|
|
15
|
+
console.error('');
|
|
16
|
+
console.error(getHelpText());
|
|
17
|
+
process.exitCode = 1;
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
const provider = createProvider(config);
|
|
21
|
+
const started = await provider.start();
|
|
22
|
+
const metadata = await fetch(`${started.issuer}/.well-known/openid-configuration`).then((res) => res.json());
|
|
23
|
+
console.log('mock-oidc-provider is running');
|
|
24
|
+
console.log('');
|
|
25
|
+
console.log(`Issuer: ${started.issuer}`);
|
|
26
|
+
console.log(`Client ID: ${config.clientId}`);
|
|
27
|
+
console.log(`Authorize: ${metadata['authorization_endpoint']}`);
|
|
28
|
+
console.log(`Token: ${metadata['token_endpoint']}`);
|
|
29
|
+
console.log(`JWKS: ${metadata['jwks_uri']}`);
|
|
30
|
+
console.log('');
|
|
31
|
+
console.log('Example client app env:');
|
|
32
|
+
console.log(`OIDC_MOCK_ISSUER=${started.issuer}`);
|
|
33
|
+
console.log(`OIDC_CLIENT_ID=${config.clientId}`);
|
|
34
|
+
console.log('');
|
|
35
|
+
console.log('Configured claims:');
|
|
36
|
+
console.log(JSON.stringify(config.claims, null, 2));
|
|
37
|
+
console.log('');
|
|
38
|
+
console.log('Press Ctrl+C to stop.');
|
|
39
|
+
const shutdown = async () => {
|
|
40
|
+
await provider.stop();
|
|
41
|
+
process.exit(0);
|
|
42
|
+
};
|
|
43
|
+
process.once('SIGINT', () => {
|
|
44
|
+
void shutdown();
|
|
45
|
+
});
|
|
46
|
+
process.once('SIGTERM', () => {
|
|
47
|
+
void shutdown();
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
main().catch((error) => {
|
|
51
|
+
console.error(error);
|
|
52
|
+
process.exit(1);
|
|
53
|
+
});
|
|
54
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
|
package/dist/config.d.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export interface ProviderConfig {
|
|
2
|
+
host: string;
|
|
3
|
+
port: number;
|
|
4
|
+
issuer: string;
|
|
5
|
+
clientId: string;
|
|
6
|
+
redirectUris: string[];
|
|
7
|
+
claims: Record<string, unknown>;
|
|
8
|
+
}
|
|
9
|
+
export declare function parseArgs(args: string[]): ProviderConfig;
|
|
10
|
+
export declare class HelpRequested extends Error {
|
|
11
|
+
constructor();
|
|
12
|
+
}
|
|
13
|
+
export declare function getHelpText(): string;
|
package/dist/config.js
ADDED
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
const defaultHost = '127.0.0.1';
|
|
2
|
+
const defaultPort = 4010;
|
|
3
|
+
const defaultClientId = 'mock-oidc-client';
|
|
4
|
+
const defaultClaims = {
|
|
5
|
+
sub: 'mock-user',
|
|
6
|
+
name: 'Mock User',
|
|
7
|
+
email: 'mock.user@example.test',
|
|
8
|
+
};
|
|
9
|
+
export function parseArgs(args) {
|
|
10
|
+
let host = defaultHost;
|
|
11
|
+
let port = defaultPort;
|
|
12
|
+
let clientId = defaultClientId;
|
|
13
|
+
let issuer;
|
|
14
|
+
const redirectUris = ['http://localhost:3000/api/auth/callback/oidc'];
|
|
15
|
+
const claims = { ...defaultClaims };
|
|
16
|
+
for (let index = 0; index < args.length; index += 1) {
|
|
17
|
+
const arg = args[index];
|
|
18
|
+
if (arg === '--host') {
|
|
19
|
+
host = readValue(args, (index += 1), arg);
|
|
20
|
+
continue;
|
|
21
|
+
}
|
|
22
|
+
if (arg === '--port') {
|
|
23
|
+
port = parsePort(readValue(args, (index += 1), arg));
|
|
24
|
+
continue;
|
|
25
|
+
}
|
|
26
|
+
if (arg === '--issuer') {
|
|
27
|
+
issuer = normalizeIssuer(readValue(args, (index += 1), arg));
|
|
28
|
+
assertRootIssuer(issuer);
|
|
29
|
+
continue;
|
|
30
|
+
}
|
|
31
|
+
if (arg === '--client-id') {
|
|
32
|
+
clientId = readValue(args, (index += 1), arg);
|
|
33
|
+
continue;
|
|
34
|
+
}
|
|
35
|
+
if (arg === '--redirect-uri') {
|
|
36
|
+
const redirectUri = readValue(args, (index += 1), arg);
|
|
37
|
+
assertLocalRedirectUri(redirectUri);
|
|
38
|
+
redirectUris.push(redirectUri);
|
|
39
|
+
continue;
|
|
40
|
+
}
|
|
41
|
+
if (arg === '--claim') {
|
|
42
|
+
const [key, value] = parseClaim(readValue(args, (index += 1), arg));
|
|
43
|
+
claims[key] = value;
|
|
44
|
+
continue;
|
|
45
|
+
}
|
|
46
|
+
if (arg === '--help' || arg === '-h') {
|
|
47
|
+
throw new HelpRequested();
|
|
48
|
+
}
|
|
49
|
+
throw new Error(`Unknown option: ${arg}`);
|
|
50
|
+
}
|
|
51
|
+
for (const redirectUri of redirectUris) {
|
|
52
|
+
assertLocalRedirectUri(redirectUri);
|
|
53
|
+
}
|
|
54
|
+
return {
|
|
55
|
+
host,
|
|
56
|
+
port,
|
|
57
|
+
issuer: issuer ?? `http://localhost:${port}`,
|
|
58
|
+
clientId,
|
|
59
|
+
redirectUris: [...new Set(redirectUris)],
|
|
60
|
+
claims,
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
export class HelpRequested extends Error {
|
|
64
|
+
constructor() {
|
|
65
|
+
super('Help requested');
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
export function getHelpText() {
|
|
69
|
+
return `mock-oidc-provider
|
|
70
|
+
|
|
71
|
+
Usage:
|
|
72
|
+
mock-oidc-provider [options]
|
|
73
|
+
|
|
74
|
+
Options:
|
|
75
|
+
--host <host> Bind host. Default: ${defaultHost}
|
|
76
|
+
--port <port> Bind port. Default: ${defaultPort}
|
|
77
|
+
--issuer <url> Issuer URL. Default: http://localhost:<port>
|
|
78
|
+
--client-id <id> Client ID. Default: ${defaultClientId}
|
|
79
|
+
--redirect-uri <uri> Additional allowed localhost redirect URI.
|
|
80
|
+
--claim <key=value> Add or override an ID token claim. Repeatable.
|
|
81
|
+
-h, --help Show help.
|
|
82
|
+
|
|
83
|
+
Example:
|
|
84
|
+
mock-oidc-provider --claim preferred_username=test.user --claim name="Test User"
|
|
85
|
+
`;
|
|
86
|
+
}
|
|
87
|
+
function readValue(args, index, flag) {
|
|
88
|
+
const value = args[index];
|
|
89
|
+
if (!value || value.startsWith('--')) {
|
|
90
|
+
throw new Error(`${flag} requires a value`);
|
|
91
|
+
}
|
|
92
|
+
return value;
|
|
93
|
+
}
|
|
94
|
+
function parsePort(value) {
|
|
95
|
+
const port = Number(value);
|
|
96
|
+
if (!Number.isInteger(port) || port < 0 || port > 65535) {
|
|
97
|
+
throw new Error(`Invalid port: ${value}`);
|
|
98
|
+
}
|
|
99
|
+
return port;
|
|
100
|
+
}
|
|
101
|
+
function parseClaim(value) {
|
|
102
|
+
const equalsIndex = value.indexOf('=');
|
|
103
|
+
if (equalsIndex <= 0) {
|
|
104
|
+
throw new Error(`Claim must use key=value format: ${value}`);
|
|
105
|
+
}
|
|
106
|
+
const key = value.slice(0, equalsIndex).trim();
|
|
107
|
+
const rawValue = value.slice(equalsIndex + 1);
|
|
108
|
+
if (!key) {
|
|
109
|
+
throw new Error(`Claim must use key=value format: ${value}`);
|
|
110
|
+
}
|
|
111
|
+
return [key, coerceClaimValue(rawValue)];
|
|
112
|
+
}
|
|
113
|
+
function coerceClaimValue(value) {
|
|
114
|
+
if (value === 'true')
|
|
115
|
+
return true;
|
|
116
|
+
if (value === 'false')
|
|
117
|
+
return false;
|
|
118
|
+
if (value === 'null')
|
|
119
|
+
return null;
|
|
120
|
+
if (/^-?\d+(\.\d+)?$/.test(value))
|
|
121
|
+
return Number(value);
|
|
122
|
+
return value;
|
|
123
|
+
}
|
|
124
|
+
function normalizeIssuer(value) {
|
|
125
|
+
return value.replace(/\/+$/, '');
|
|
126
|
+
}
|
|
127
|
+
function assertRootIssuer(value) {
|
|
128
|
+
const url = new URL(value);
|
|
129
|
+
if (url.pathname !== '/' && url.pathname !== '') {
|
|
130
|
+
throw new Error(`Issuer URL must not have a path component: ${value}`);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
function assertLocalRedirectUri(value) {
|
|
134
|
+
let url;
|
|
135
|
+
try {
|
|
136
|
+
url = new URL(value);
|
|
137
|
+
}
|
|
138
|
+
catch {
|
|
139
|
+
throw new Error(`Redirect URI must be a valid localhost URL: ${value}`);
|
|
140
|
+
}
|
|
141
|
+
const isLocalHost = url.hostname === 'localhost' || url.hostname === '127.0.0.1' || url.hostname === '[::1]';
|
|
142
|
+
if (!isLocalHost) {
|
|
143
|
+
throw new Error(`Redirect URI must use localhost or 127.0.0.1: ${value}`);
|
|
144
|
+
}
|
|
145
|
+
if (url.protocol !== 'http:' && url.protocol !== 'https:') {
|
|
146
|
+
throw new Error(`Redirect URI must use http or https: ${value}`);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { ProviderConfig } from './config.js';
|
|
2
|
+
interface StartedProvider {
|
|
3
|
+
issuer: string;
|
|
4
|
+
stop: () => Promise<void>;
|
|
5
|
+
}
|
|
6
|
+
export declare function createProvider(config: ProviderConfig): {
|
|
7
|
+
start: () => Promise<StartedProvider>;
|
|
8
|
+
stop: () => Promise<void>;
|
|
9
|
+
};
|
|
10
|
+
export {};
|
package/dist/provider.js
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { OAuth2Server } from 'oauth2-mock-server';
|
|
2
|
+
export function createProvider(config) {
|
|
3
|
+
const server = new OAuth2Server(undefined, undefined, { endpoints: { jwks: '/discovery/v2.0/keys' } });
|
|
4
|
+
server.service.on('beforeTokenSigning', (token) => {
|
|
5
|
+
Object.assign(token.payload, config.claims);
|
|
6
|
+
});
|
|
7
|
+
async function start() {
|
|
8
|
+
await server.issuer.keys.generate('RS256');
|
|
9
|
+
await server.start(config.port, config.host);
|
|
10
|
+
const issuerUrl = new URL(config.issuer);
|
|
11
|
+
issuerUrl.port = String(server.address().port);
|
|
12
|
+
const issuer = issuerUrl.toString().replace(/\/$/, '');
|
|
13
|
+
server.issuer.url = issuer;
|
|
14
|
+
return { issuer, stop };
|
|
15
|
+
}
|
|
16
|
+
async function stop() {
|
|
17
|
+
await server.stop();
|
|
18
|
+
}
|
|
19
|
+
return { start, stop };
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=provider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"provider.js","sourceRoot":"","sources":["../src/provider.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AASlD,MAAM,UAAU,cAAc,CAAC,MAAsB;IACnD,MAAM,MAAM,GAAG,IAAI,YAAY,CAAC,SAAS,EAAE,SAAS,EAAE,EAAE,SAAS,EAAE,EAAE,IAAI,EAAE,sBAAsB,EAAE,EAAE,CAAC,CAAC;IAEvG,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC,oBAAoB,EAAE,CAAC,KAAK,EAAE,EAAE;QAChD,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC;IAC9C,CAAC,CAAC,CAAC;IAEH,KAAK,UAAU,KAAK;QAClB,MAAM,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;QAC3C,MAAM,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC;QAE7C,MAAM,SAAS,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QACzC,SAAS,CAAC,IAAI,GAAG,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC,IAAI,CAAC,CAAC;QAC/C,MAAM,MAAM,GAAG,SAAS,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;QACvD,MAAM,CAAC,MAAM,CAAC,GAAG,GAAG,MAAM,CAAC;QAE3B,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;IAC1B,CAAC;IAED,KAAK,UAAU,IAAI;QACjB,MAAM,MAAM,CAAC,IAAI,EAAE,CAAC;IACtB,CAAC;IAED,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;AACzB,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@cheellipadi/mock-oidc-provider",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Local OIDC provider for development and testing.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"keywords": [
|
|
7
|
+
"oidc",
|
|
8
|
+
"oauth2",
|
|
9
|
+
"mock",
|
|
10
|
+
"local-development",
|
|
11
|
+
"pkce"
|
|
12
|
+
],
|
|
13
|
+
"type": "module",
|
|
14
|
+
"bin": {
|
|
15
|
+
"mock-oidc-provider": "dist/cli.js"
|
|
16
|
+
},
|
|
17
|
+
"files": [
|
|
18
|
+
"dist",
|
|
19
|
+
"README.md"
|
|
20
|
+
],
|
|
21
|
+
"dependencies": {
|
|
22
|
+
"oauth2-mock-server": "^8.2.3"
|
|
23
|
+
},
|
|
24
|
+
"devDependencies": {
|
|
25
|
+
"@types/node": "^24.10.1",
|
|
26
|
+
"jose": "^6.1.3",
|
|
27
|
+
"tsx": "^4.20.6",
|
|
28
|
+
"typescript": "^5.9.3",
|
|
29
|
+
"vitest": "^4.0.13"
|
|
30
|
+
},
|
|
31
|
+
"engines": {
|
|
32
|
+
"node": ">=22"
|
|
33
|
+
},
|
|
34
|
+
"scripts": {
|
|
35
|
+
"build": "tsc -p tsconfig.json",
|
|
36
|
+
"dev": "tsx src/cli.ts",
|
|
37
|
+
"test": "vitest run",
|
|
38
|
+
"typecheck": "tsc --noEmit",
|
|
39
|
+
"pack:dry-run": "pnpm pack --dry-run"
|
|
40
|
+
}
|
|
41
|
+
}
|