@samebase/identity-broker 0.0.0-stage → 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.
Files changed (82) hide show
  1. package/LICENSE +201 -0
  2. package/NOTICE +4 -0
  3. package/README.md +90 -2
  4. package/dist/cli/index.d.ts +2 -0
  5. package/dist/cli/index.js +26 -0
  6. package/dist/cli/index.js.map +1 -0
  7. package/dist/client/connectors/email.d.ts +6 -0
  8. package/dist/client/connectors/email.js +5 -0
  9. package/dist/client/connectors/email.js.map +1 -0
  10. package/dist/client/connectors/github.d.ts +7 -0
  11. package/dist/client/connectors/github.js +57 -0
  12. package/dist/client/connectors/github.js.map +1 -0
  13. package/dist/client/connectors/google.d.ts +7 -0
  14. package/dist/client/connectors/google.js +13 -0
  15. package/dist/client/connectors/google.js.map +1 -0
  16. package/dist/client/connectors/types.d.ts +47 -0
  17. package/dist/client/connectors/types.js +2 -0
  18. package/dist/client/connectors/types.js.map +1 -0
  19. package/dist/client/connectors/upstream.d.ts +25 -0
  20. package/dist/client/connectors/upstream.js +86 -0
  21. package/dist/client/connectors/upstream.js.map +1 -0
  22. package/dist/client/html.d.ts +30 -0
  23. package/dist/client/html.js +84 -0
  24. package/dist/client/html.js.map +1 -0
  25. package/dist/client/index.d.ts +78 -0
  26. package/dist/client/index.js +721 -0
  27. package/dist/client/index.js.map +1 -0
  28. package/dist/client/jwt.d.ts +31 -0
  29. package/dist/client/jwt.js +55 -0
  30. package/dist/client/jwt.js.map +1 -0
  31. package/dist/client/keys.d.ts +44 -0
  32. package/dist/client/keys.js +130 -0
  33. package/dist/client/keys.js.map +1 -0
  34. package/dist/client/protocol.d.ts +75 -0
  35. package/dist/client/protocol.js +259 -0
  36. package/dist/client/protocol.js.map +1 -0
  37. package/dist/client/responses.d.ts +24 -0
  38. package/dist/client/responses.js +57 -0
  39. package/dist/client/responses.js.map +1 -0
  40. package/dist/client/subject.d.ts +15 -0
  41. package/dist/client/subject.js +32 -0
  42. package/dist/client/subject.js.map +1 -0
  43. package/dist/component/_generated/api.d.ts +45 -0
  44. package/dist/component/_generated/api.js +31 -0
  45. package/dist/component/_generated/api.js.map +1 -0
  46. package/dist/component/_generated/component.d.ts +375 -0
  47. package/dist/component/_generated/component.js +11 -0
  48. package/dist/component/_generated/component.js.map +1 -0
  49. package/dist/component/_generated/dataModel.d.ts +45 -0
  50. package/dist/component/_generated/dataModel.js +11 -0
  51. package/dist/component/_generated/dataModel.js.map +1 -0
  52. package/dist/component/_generated/server.d.ts +132 -0
  53. package/dist/component/_generated/server.js +80 -0
  54. package/dist/component/_generated/server.js.map +1 -0
  55. package/dist/component/apps.d.ts +36 -0
  56. package/dist/component/apps.js +124 -0
  57. package/dist/component/apps.js.map +1 -0
  58. package/dist/component/authRequests.d.ts +254 -0
  59. package/dist/component/authRequests.js +392 -0
  60. package/dist/component/authRequests.js.map +1 -0
  61. package/dist/component/clients.d.ts +43 -0
  62. package/dist/component/clients.js +95 -0
  63. package/dist/component/clients.js.map +1 -0
  64. package/dist/component/convex.config.d.ts +2 -0
  65. package/dist/component/convex.config.js +3 -0
  66. package/dist/component/convex.config.js.map +1 -0
  67. package/dist/component/crypto.d.ts +2 -0
  68. package/dist/component/crypto.js +9 -0
  69. package/dist/component/crypto.js.map +1 -0
  70. package/dist/component/lifecycle.d.ts +15 -0
  71. package/dist/component/lifecycle.js +59 -0
  72. package/dist/component/lifecycle.js.map +1 -0
  73. package/dist/component/registration.d.ts +17 -0
  74. package/dist/component/registration.js +57 -0
  75. package/dist/component/registration.js.map +1 -0
  76. package/dist/component/schema.d.ts +650 -0
  77. package/dist/component/schema.js +122 -0
  78. package/dist/component/schema.js.map +1 -0
  79. package/dist/component/signIns.d.ts +8 -0
  80. package/dist/component/signIns.js +26 -0
  81. package/dist/component/signIns.js.map +1 -0
  82. package/package.json +51 -3
@@ -0,0 +1,30 @@
1
+ /** The few pages the broker renders itself. Plain HTML, one stylesheet, no script. */
2
+ export declare function page(title: string, body: string): Response;
3
+ /**
4
+ * The connector choice. A third-party app gets the consent wording and a deny link; a first-party
5
+ * app only sees the buttons.
6
+ */
7
+ export declare function chooserPage(args: {
8
+ appName: string;
9
+ firstParty: boolean;
10
+ connectors: Array<{
11
+ name: string;
12
+ label: string;
13
+ href: string;
14
+ }>;
15
+ denyHref: string;
16
+ }): Response;
17
+ export declare function emailAddressPage(args: {
18
+ appName: string;
19
+ action: string;
20
+ requestId: string;
21
+ error?: string;
22
+ }): Response;
23
+ export declare function emailCodePage(args: {
24
+ appName: string;
25
+ action: string;
26
+ requestId: string;
27
+ email: string;
28
+ error?: string;
29
+ }): Response;
30
+ export declare function errorPage(title: string, message: string, status?: number): Response;
@@ -0,0 +1,84 @@
1
+ /** The few pages the broker renders itself. Plain HTML, one stylesheet, no script. */
2
+ function escape(value) {
3
+ return value
4
+ .replace(/&/g, "&amp;")
5
+ .replace(/</g, "&lt;")
6
+ .replace(/>/g, "&gt;")
7
+ .replace(/"/g, "&quot;");
8
+ }
9
+ const STYLE = `
10
+ body { margin: 0; font: 16px/1.5 system-ui, sans-serif; color: #111; background: #fff; }
11
+ main { max-width: 24rem; margin: 10vh auto; padding: 0 1rem; }
12
+ h1 { font-size: 1.25rem; font-weight: 600; }
13
+ p { margin: 0.5rem 0; }
14
+ .list { display: grid; gap: 0.5rem; margin: 1.5rem 0; }
15
+ a.button, button { display: block; width: 100%; box-sizing: border-box; padding: 0.75rem 1rem;
16
+ font: inherit; color: #111; background: #fff; border: 1px solid #111; text-align: center;
17
+ text-decoration: none; cursor: pointer; }
18
+ input { display: block; width: 100%; box-sizing: border-box; padding: 0.75rem 1rem; font: inherit;
19
+ border: 1px solid #111; margin: 1rem 0; }
20
+ .error { color: #b00020; }
21
+ .muted { color: #555; }
22
+ `;
23
+ export function page(title, body) {
24
+ const html = `<!doctype html>
25
+ <html lang="en">
26
+ <head>
27
+ <meta charset="utf-8">
28
+ <meta name="viewport" content="width=device-width, initial-scale=1">
29
+ <meta name="robots" content="noindex">
30
+ <title>${escape(title)}</title>
31
+ <style>${STYLE}</style>
32
+ </head>
33
+ <body><main>${body}</main></body>
34
+ </html>`;
35
+ return new Response(html, {
36
+ status: 200,
37
+ headers: {
38
+ "Content-Type": "text/html; charset=utf-8",
39
+ "Cache-Control": "no-store",
40
+ "Referrer-Policy": "no-referrer",
41
+ },
42
+ });
43
+ }
44
+ /**
45
+ * The connector choice. A third-party app gets the consent wording and a deny link; a first-party
46
+ * app only sees the buttons.
47
+ */
48
+ export function chooserPage(args) {
49
+ const buttons = args.connectors
50
+ .map((connector) => `<a class="button" href="${escape(connector.href)}">Continue with ${escape(connector.label)}</a>`)
51
+ .join("\n");
52
+ const consent = args.firstParty
53
+ ? ""
54
+ : `<p class="muted">${escape(args.appName)} will receive your identity from the provider you choose: a stable id, your name, and your verified email address.</p>`;
55
+ const deny = args.firstParty
56
+ ? ""
57
+ : `<p><a href="${escape(args.denyHref)}">Cancel and return to ${escape(args.appName)}</a></p>`;
58
+ return page(`Sign in to ${args.appName}`, `<h1>Sign in to ${escape(args.appName)}</h1>${consent}<div class="list">${buttons}</div>${deny}`);
59
+ }
60
+ export function emailAddressPage(args) {
61
+ const error = args.error === undefined ? "" : `<p class="error">${escape(args.error)}</p>`;
62
+ return page(`Sign in to ${args.appName}`, `<h1>Sign in to ${escape(args.appName)}</h1><p>Enter your email address. A six-digit code is sent to it.</p>${error}
63
+ <form method="post" action="${escape(args.action)}">
64
+ <input type="hidden" name="request" value="${escape(args.requestId)}">
65
+ <input type="hidden" name="step" value="send">
66
+ <input type="email" name="email" required autocomplete="email" autofocus placeholder="you@example.com">
67
+ <button type="submit">Send code</button>
68
+ </form>`);
69
+ }
70
+ export function emailCodePage(args) {
71
+ const error = args.error === undefined ? "" : `<p class="error">${escape(args.error)}</p>`;
72
+ return page(`Sign in to ${args.appName}`, `<h1>Check your email</h1><p>Enter the six-digit code sent to ${escape(args.email)}.</p>${error}
73
+ <form method="post" action="${escape(args.action)}">
74
+ <input type="hidden" name="request" value="${escape(args.requestId)}">
75
+ <input type="hidden" name="step" value="verify">
76
+ <input type="text" name="code" inputmode="numeric" pattern="[0-9]{6}" required autocomplete="one-time-code" autofocus placeholder="000000">
77
+ <button type="submit">Continue</button>
78
+ </form>`);
79
+ }
80
+ export function errorPage(title, message, status = 400) {
81
+ const response = page(title, `<h1>${escape(title)}</h1><p>${escape(message)}</p>`);
82
+ return new Response(response.body, { status, headers: response.headers });
83
+ }
84
+ //# sourceMappingURL=html.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"html.js","sourceRoot":"","sources":["../../src/client/html.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,78 @@
1
+ import { type HttpRouter } from "convex/server";
2
+ import type { ComponentApi } from "../component/_generated/component.js";
3
+ import type { Connector } from "./connectors/types.js";
4
+ export type { Connector, EmailConnector, OauthConnector, OidcConnector, SendEmailCode, UpstreamIdentity, } from "./connectors/types.js";
5
+ export { github } from "./connectors/github.js";
6
+ export { google } from "./connectors/google.js";
7
+ export { email } from "./connectors/email.js";
8
+ export { createKeySet, rotateKeySet, type KeySet } from "./keys.js";
9
+ export type IdentityBrokerConfig = {
10
+ /** `components.identityBroker` of the host app. */
11
+ component: ComponentApi;
12
+ /** The issuer URL, host-only or with a path, e.g. `https://auth.example.com`. */
13
+ issuer: string;
14
+ /** The content of `IDENTITY_BROKER_KEYS`, read in the request. */
15
+ keys: () => string | undefined;
16
+ connectors: Connector[];
17
+ };
18
+ /** Lifecycle values the host's cron passes to `cleanup`. */
19
+ export declare const PREVIEW_CLIENT_MAX_AGE_MS: number;
20
+ export declare const SIGN_IN_RETENTION_MS: number;
21
+ export declare function defineIdentityBroker(config: IdentityBrokerConfig): {
22
+ /** Mounts every endpoint on the host's router. */
23
+ addHttpRoutes(http: HttpRouter): void;
24
+ /**
25
+ * Administration as internal functions of the host, for `npx convex run`: export them from a
26
+ * host module such as `convex/identityBroker.ts`.
27
+ */
28
+ admin(): {
29
+ createApp: import("convex/server").RegisteredMutation<"internal", {
30
+ allowedCallbackHosts: string[];
31
+ firstParty: boolean;
32
+ name: string;
33
+ }, Promise<{
34
+ appId: string;
35
+ }>>;
36
+ mintRegistrationToken: import("convex/server").RegisteredMutation<"internal", {
37
+ appId: string;
38
+ expiresInDays?: number;
39
+ }, Promise<{
40
+ token: string;
41
+ expiresAt: number;
42
+ }>>;
43
+ setAllowedCallbackHosts: import("convex/server").RegisteredMutation<"internal", {
44
+ allowedCallbackHosts: string[];
45
+ appId: string;
46
+ }, Promise<null>>;
47
+ deleteApp: import("convex/server").RegisteredMutation<"internal", {
48
+ appId: string;
49
+ }, Promise<null>>;
50
+ listApps: import("convex/server").RegisteredQuery<"internal", {}, Promise<{
51
+ allowedCallbackHosts: Array<string>;
52
+ appId: string;
53
+ createdAt: number;
54
+ firstParty: boolean;
55
+ name: string;
56
+ }[]>>;
57
+ listClients: import("convex/server").RegisteredQuery<"internal", {
58
+ appId: string;
59
+ }, Promise<{
60
+ appId: string;
61
+ clientId: string;
62
+ clientName: string;
63
+ createdAt: number;
64
+ deploymentType: "production" | "development" | "preview";
65
+ lastSignInAt?: number;
66
+ redirectUri: string;
67
+ secretHash: string;
68
+ softwareVersion: string;
69
+ tokenEndpointAuthMethod: "client_secret_post" | "client_secret_basic";
70
+ }[]>>;
71
+ cleanup: import("convex/server").RegisteredMutation<"internal", {}, Promise<{
72
+ authRequests: number;
73
+ authorizationCodes: number;
74
+ previewClients: number;
75
+ signIns: number;
76
+ }>>;
77
+ };
78
+ };