@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,122 @@
1
+ import { defineSchema, defineTable } from "convex/server";
2
+ import { v } from "convex/values";
3
+ const { array, boolean, literal, number, object, optional, string, union } = v;
4
+ /** How a client authenticates at the token endpoint. Public clients are not supported yet. */
5
+ export const vTokenEndpointAuthMethod = union(literal("client_secret_post"), literal("client_secret_basic"));
6
+ /** The deployment a client stands for. Preview clients are pruned; the others are deleted by hand. */
7
+ export const vDeploymentType = union(literal("production"), literal("development"), literal("preview"));
8
+ /**
9
+ * What a connector attested about the user. `upstreamId` is the connector's own stable id for the
10
+ * account (the GitHub user id, the OIDC `sub`, the canonical email address). The pairwise subject
11
+ * is derived from it on the host, where the salt lives.
12
+ */
13
+ export const vUpstreamIdentity = object({
14
+ connector: string(),
15
+ upstreamId: string(),
16
+ email: optional(string()),
17
+ emailVerified: optional(boolean()),
18
+ name: optional(string()),
19
+ picture: optional(string()),
20
+ });
21
+ /** The fields every authorization request carries from `/authorize` until it is deleted. */
22
+ const authRequestFields = {
23
+ requestId: string(),
24
+ appId: string(),
25
+ clientId: string(),
26
+ redirectUri: string(),
27
+ scope: string(),
28
+ state: optional(string()),
29
+ nonce: optional(string()),
30
+ codeChallenge: string(),
31
+ /** `prompt=login` or `max_age` was sent: the connector must reauthenticate or refuse. */
32
+ freshLogin: boolean(),
33
+ createdAt: number(),
34
+ expiresAt: number(),
35
+ };
36
+ export const vAuthRequest = union(
37
+ // Stored by /authorize; the user has not chosen a connector yet.
38
+ object({ status: literal("pending"), ...authRequestFields }),
39
+ // Redirected to an OAuth or OIDC connector; its callback claims the request by the state hash.
40
+ object({
41
+ status: literal("upstream"),
42
+ ...authRequestFields,
43
+ connector: string(),
44
+ upstreamStateHash: string(),
45
+ upstreamCodeVerifier: string(),
46
+ upstreamNonce: optional(string()),
47
+ }),
48
+ // The connector callback arrived and the code exchange is running; a replay finds this and stops.
49
+ object({ status: literal("claimed"), ...authRequestFields, connector: string() }),
50
+ // An email code was sent; the user types it.
51
+ object({
52
+ status: literal("emailSent"),
53
+ ...authRequestFields,
54
+ connector: string(),
55
+ email: string(),
56
+ emailCodeHash: string(),
57
+ emailCodeExpiresAt: number(),
58
+ emailAttempts: number(),
59
+ }),
60
+ // The connector attested the identity; the authorization code points here until it is exchanged.
61
+ object({
62
+ status: literal("completed"),
63
+ ...authRequestFields,
64
+ identity: vUpstreamIdentity,
65
+ authTime: number(),
66
+ }));
67
+ export default defineSchema({
68
+ apps: defineTable({
69
+ appId: string(),
70
+ name: string(),
71
+ firstParty: boolean(),
72
+ /** Exact hosts or `*.suffix` patterns a client callback may use, e.g. `*.convex.site`. */
73
+ allowedCallbackHosts: array(string()),
74
+ createdAt: number(),
75
+ }).index("by_app_id", ["appId"]),
76
+ registrationTokens: defineTable({
77
+ tokenHash: string(),
78
+ appId: string(),
79
+ expiresAt: number(),
80
+ createdAt: number(),
81
+ })
82
+ .index("by_token_hash", ["tokenHash"])
83
+ .index("by_app_id", ["appId"]),
84
+ clients: defineTable({
85
+ clientId: string(),
86
+ appId: string(),
87
+ secretHash: string(),
88
+ tokenEndpointAuthMethod: vTokenEndpointAuthMethod,
89
+ redirectUri: string(),
90
+ deploymentType: vDeploymentType,
91
+ clientName: string(),
92
+ softwareVersion: string(),
93
+ createdAt: number(),
94
+ lastSignInAt: optional(number()),
95
+ })
96
+ .index("by_client_id", ["clientId"])
97
+ .index("by_app_id", ["appId"])
98
+ .index("by_deployment_type", ["deploymentType"]),
99
+ authRequests: defineTable(vAuthRequest)
100
+ .index("by_request_id", ["requestId"])
101
+ .index("by_upstream_state_hash", ["upstreamStateHash"])
102
+ .index("by_expires_at", ["expiresAt"]),
103
+ authorizationCodes: defineTable({
104
+ codeHash: string(),
105
+ authRequestId: v.id("authRequests"),
106
+ clientId: string(),
107
+ expiresAt: number(),
108
+ usedAt: optional(number()),
109
+ })
110
+ .index("by_code_hash", ["codeHash"])
111
+ .index("by_expires_at", ["expiresAt"]),
112
+ signIns: defineTable({
113
+ appId: string(),
114
+ clientId: string(),
115
+ connector: string(),
116
+ sub: string(),
117
+ at: number(),
118
+ })
119
+ .index("by_app_id_and_at", ["appId", "at"])
120
+ .index("by_at", ["at"]),
121
+ });
122
+ //# sourceMappingURL=schema.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema.js","sourceRoot":"","sources":["../../src/component/schema.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ /** One audit row per issued id_token: no email, no name, no token. Also marks the client as used. */
2
+ export declare const record: import("convex/server").RegisteredMutation<"public", {
3
+ appId: string;
4
+ at: number;
5
+ clientId: string;
6
+ connector: string;
7
+ sub: string;
8
+ }, Promise<null>>;
@@ -0,0 +1,26 @@
1
+ import { v } from "convex/values";
2
+ import { mutation } from "./_generated/server";
3
+ const { number, string } = v;
4
+ /** One audit row per issued id_token: no email, no name, no token. Also marks the client as used. */
5
+ export const record = mutation({
6
+ args: { appId: string(), clientId: string(), connector: string(), sub: string(), at: number() },
7
+ returns: v.null(),
8
+ handler: async (ctx, args) => {
9
+ await ctx.db.insert("signIns", {
10
+ appId: args.appId,
11
+ clientId: args.clientId,
12
+ connector: args.connector,
13
+ sub: args.sub,
14
+ at: args.at,
15
+ });
16
+ const client = await ctx.db
17
+ .query("clients")
18
+ .withIndex("by_client_id", (q) => q.eq("clientId", args.clientId))
19
+ .unique();
20
+ if (client !== null) {
21
+ await ctx.db.patch("clients", client._id, { lastSignInAt: args.at });
22
+ }
23
+ return null;
24
+ },
25
+ });
26
+ //# sourceMappingURL=signIns.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"signIns.js","sourceRoot":"","sources":["../../src/component/signIns.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,eAAe,CAAC;AAClC,OAAO,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAE/C,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,CAAC,CAAC;AAE7B,qGAAqG;AACrG,MAAM,CAAC,MAAM,MAAM,GAAG,QAAQ,CAAC;IAC7B,IAAI,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,SAAS,EAAE,MAAM,EAAE,EAAE,GAAG,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE;IAC/F,OAAO,EAAE,CAAC,CAAC,IAAI,EAAE;IACjB,OAAO,EAAE,KAAK,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE;QAC3B,MAAM,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC,SAAS,EAAE;YAC7B,KAAK,EAAE,IAAI,CAAC,KAAK;YACjB,QAAQ,EAAE,IAAI,CAAC,QAAQ;YACvB,SAAS,EAAE,IAAI,CAAC,SAAS;YACzB,GAAG,EAAE,IAAI,CAAC,GAAG;YACb,EAAE,EAAE,IAAI,CAAC,EAAE;SACZ,CAAC,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,GAAG,CAAC,EAAE;aACxB,KAAK,CAAC,SAAS,CAAC;aAChB,SAAS,CAAC,cAAc,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,UAAU,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC;aACjE,MAAM,EAAE,CAAC;QACZ,IAAI,MAAM,KAAK,IAAI,EAAE,CAAC;YACpB,MAAM,GAAG,CAAC,EAAE,CAAC,KAAK,CAAC,SAAS,EAAE,MAAM,CAAC,GAAG,EAAE,EAAE,YAAY,EAAE,IAAI,CAAC,EAAE,EAAE,CAAC,CAAC;QACvE,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;CACF,CAAC,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,54 @@
1
1
  {
2
2
  "name": "@samebase/identity-broker",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
3
+ "version": "0.1.0",
4
+ "description": "An OpenID Provider for Convex that holds a team's upstream sign-in connections once and keeps no user accounts.",
5
+ "license": "Apache-2.0",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "git+https://github.com/samebase/identity-broker.git",
9
+ "directory": "packages/identity-broker"
10
+ },
11
+ "bin": {
12
+ "identity-broker": "./dist/cli/index.js"
13
+ },
14
+ "files": [
15
+ "dist",
16
+ "LICENSE",
17
+ "NOTICE",
18
+ "README.md"
19
+ ],
20
+ "type": "module",
21
+ "exports": {
22
+ ".": {
23
+ "types": "./dist/client/index.d.ts",
24
+ "default": "./dist/client/index.js"
25
+ },
26
+ "./convex.config": {
27
+ "types": "./dist/component/convex.config.d.ts",
28
+ "default": "./dist/component/convex.config.js"
29
+ },
30
+ "./_generated/component.js": {
31
+ "types": "./dist/component/_generated/component.d.ts"
32
+ }
33
+ },
34
+ "dependencies": {
35
+ "jose": "6.2.13",
36
+ "oauth4webapi": "3.8.8"
37
+ },
38
+ "devDependencies": {
39
+ "@types/node": "24.19.2",
40
+ "convex": "1.47.0",
41
+ "convex-test": "0.0.61",
42
+ "openid-client": "6.8.8",
43
+ "typescript": "7.0.2",
44
+ "vite-plus": "1.3.0"
45
+ },
46
+ "peerDependencies": {
47
+ "convex": "^1.47.0"
48
+ },
49
+ "scripts": {
50
+ "build": "tsc --build ./tsconfig.build.json --force",
51
+ "codegen": "convex codegen --component-dir ./src/component",
52
+ "typecheck": "tsc --noEmit"
53
+ }
6
54
  }