step3-social-proof.mjs201 lines · main
1/**
2 * Step 3 proof: Google/GitHub social login on Doltgres.
3 *
4 * Without real OAuth client secrets, we prove the Doltgres user/link/session
5 * path using a post-exchange profile (same as after Google/GitHub returns).
6 * Authorisation URL shape is checked with dummy env credentials.
7 *
8 * cd apps/api
9 * BRIVEN_ENGINE_DATABASE_URL=postgres://postgres:devpass@127.0.0.1:5434/briven_engine?sslmode=disable \
10 * BRIVEN_DATA_PLANE_URL=postgres://postgres:devpass@127.0.0.1:5434/postgres?sslmode=disable \
11 * bun scripts/step3-social-proof.mjs
12 */
13
14process.env.BRIVEN_AUTH_CORE_ENABLED = 'true';
15process.env.BRIVEN_ENV = 'development';
16process.env.BRIVEN_ENGINE_DATABASE_URL =
17 process.env.BRIVEN_ENGINE_DATABASE_URL ??
18 'postgres://postgres:devpass@127.0.0.1:5434/briven_engine?sslmode=disable';
19process.env.BRIVEN_DATA_PLANE_URL =
20 process.env.BRIVEN_DATA_PLANE_URL ??
21 'postgres://postgres:devpass@127.0.0.1:5434/postgres?sslmode=disable';
22// Dummy credentials so authorisation URL can be built (not used for real HTTP)
23process.env.BRIVEN_GOOGLE_CLIENT_ID =
24 process.env.BRIVEN_GOOGLE_CLIENT_ID ?? 'test-google-client-id.apps.googleusercontent.com';
25process.env.BRIVEN_GOOGLE_CLIENT_SECRET =
26 process.env.BRIVEN_GOOGLE_CLIENT_SECRET ?? 'test-google-secret';
27process.env.BRIVEN_GITHUB_CLIENT_ID =
28 process.env.BRIVEN_GITHUB_CLIENT_ID ?? 'test-github-client-id';
29process.env.BRIVEN_GITHUB_CLIENT_SECRET =
30 process.env.BRIVEN_GITHUB_CLIENT_SECRET ?? 'test-github-secret';
31
32const { ensureBrivenEngineDatabase } = await import(
33 '../src/services/auth-core/ensure-db.ts'
34);
35const { initAuthCoreSdk } = await import('../src/services/auth-core/engine.ts');
36const {
37 getAuthorisationUrl,
38 signInUpWithThirdPartyProfile,
39} = await import('../src/services/auth-core/thirdparty.ts');
40const { getEnginePool } = await import('../src/services/auth-core/db.ts');
41
42const projectId = 'p_step3_local';
43
44console.log('=== Phase 4: social login (Google/GitHub) on Doltgres ===');
45console.log({ projectId });
46
47const ensured = await ensureBrivenEngineDatabase();
48if (!ensured.ok) {
49 console.error('FAIL ensure', ensured);
50 process.exit(1);
51}
52if (!(await initAuthCoreSdk())) {
53 console.error('FAIL init');
54 process.exit(1);
55}
56
57// 1) Authorisation URLs
58const googleUrl = await getAuthorisationUrl({
59 thirdPartyId: 'google',
60 redirectURI: 'http://localhost:3000/auth/callback/google',
61 projectId,
62});
63console.log('google auth url', {
64 status: googleUrl.status,
65 hasGoogle:
66 googleUrl.status === 'OK' &&
67 googleUrl.urlWithQueryParams.includes('accounts.google.com'),
68 hasClientId:
69 googleUrl.status === 'OK' &&
70 googleUrl.urlWithQueryParams.includes('test-google-client-id'),
71 credentialsSource:
72 googleUrl.status === 'OK' ? googleUrl.credentialsSource : null,
73});
74if (googleUrl.status !== 'OK') {
75 console.error('FAIL google url', googleUrl);
76 process.exit(1);
77}
78
79const githubUrl = await getAuthorisationUrl({
80 thirdPartyId: 'github',
81 redirectURI: 'http://localhost:3000/auth/callback/github',
82 projectId,
83});
84console.log('github auth url', {
85 status: githubUrl.status,
86 hasGithub:
87 githubUrl.status === 'OK' &&
88 githubUrl.urlWithQueryParams.includes('github.com/login/oauth'),
89});
90if (githubUrl.status !== 'OK') {
91 console.error('FAIL github url', githubUrl);
92 process.exit(1);
93}
94
95// 2) Simulated Google profile (after successful OAuth exchange)
96const googleTpId = `google-sub-${Date.now()}`;
97const googleEmail = `step3_google_${Date.now()}@example.com`;
98const g1 = await signInUpWithThirdPartyProfile({
99 profile: {
100 thirdPartyId: 'google',
101 thirdPartyUserId: googleTpId,
102 email: googleEmail,
103 emailVerified: true,
104 name: 'Step3 Google User',
105 },
106 projectId,
107});
108console.log('google first sign-in', {
109 status: g1.status,
110 createdNewUser: g1.status === 'OK' ? g1.createdNewUser : null,
111 userId: g1.status === 'OK' ? g1.user.id : null,
112 session: g1.status === 'OK' ? g1.session.handle : null,
113});
114if (g1.status !== 'OK' || !g1.createdNewUser) {
115 console.error('FAIL google first', g1);
116 process.exit(1);
117}
118
119// 3) Same Google account again → same user, not new
120const g2 = await signInUpWithThirdPartyProfile({
121 profile: {
122 thirdPartyId: 'google',
123 thirdPartyUserId: googleTpId,
124 email: googleEmail,
125 emailVerified: true,
126 },
127 projectId,
128});
129console.log('google second sign-in', {
130 status: g2.status,
131 createdNewUser: g2.status === 'OK' ? g2.createdNewUser : null,
132 sameUser: g2.status === 'OK' && g2.user.id === g1.user.id,
133});
134if (g2.status !== 'OK' || g2.createdNewUser || g2.user.id !== g1.user.id) {
135 console.error('FAIL google second', g2);
136 process.exit(1);
137}
138
139// 4) GitHub profile
140const githubTpId = `gh-${Date.now()}`;
141const gh = await signInUpWithThirdPartyProfile({
142 profile: {
143 thirdPartyId: 'github',
144 thirdPartyUserId: githubTpId,
145 email: `step3_gh_${Date.now()}@example.com`,
146 emailVerified: true,
147 name: 'Step3 GH',
148 },
149 projectId,
150});
151console.log('github sign-in', {
152 status: gh.status,
153 createdNewUser: gh.status === 'OK' ? gh.createdNewUser : null,
154 userId: gh.status === 'OK' ? gh.user.id : null,
155});
156if (gh.status !== 'OK') {
157 console.error('FAIL github', gh);
158 process.exit(1);
159}
160
161// 5) SQL proof
162const pool = getEnginePool();
163const links = await pool.query(
164 `SELECT third_party_id, third_party_user_id, user_id, tenant_id
165 FROM be_third_party_links
166 WHERE tenant_id = $1
167 ORDER BY created_at`,
168 ['proj-p-step3-local'],
169);
170const sessions = await pool.query(
171 `SELECT COUNT(*)::int AS n FROM be_sessions
172 WHERE user_id = ANY($1::text[])`,
173 [[g1.user.id, gh.user.id]],
174);
175
176console.log('SQL third_party_links', links.rows);
177console.log('SQL sessions for social users', sessions.rows[0]);
178
179const hasGoogle = links.rows.some(
180 (r) => r.third_party_id === 'google' && r.third_party_user_id === googleTpId,
181);
182const hasGithub = links.rows.some(
183 (r) => r.third_party_id === 'github' && r.third_party_user_id === githubTpId,
184);
185if (!hasGoogle || !hasGithub) {
186 console.error('FAIL links missing');
187 process.exit(1);
188}
189
190console.log('');
191console.log('✔ PHASE 4 LOCAL PROOF OK (social)');
192console.log(' storage: Doltgres');
193console.log(' Google authorisation URL: OK');
194console.log(' GitHub authorisation URL: OK');
195console.log(' Google sign-up + re-login same user: OK');
196console.log(' GitHub sign-up: OK');
197console.log(' be_third_party_links rows: OK');
198console.log(' sessions: OK');
199console.log(' note: real browser OAuth needs live Google/GitHub redirect URIs;');
200console.log(' platform env BRIVEN_GOOGLE_* / BRIVEN_GITHUB_* already on France.');
201process.exit(0);