@@ -6,6 +6,12 @@ import { ConvexError } from "convex/values";
66import { internal } from "./_generated/api" ;
77import type { DataModel , Id } from "./_generated/dataModel" ;
88import { isLocalDevAuthEnabled } from "./lib/devAuth" ;
9+ import {
10+ GITHUB_ORG_MEMBERSHIP_SYNC_PROFILE_KEY ,
11+ fetchActiveGitHubOrgMemberships ,
12+ readGitHubOrgMembershipSync ,
13+ replaceGitHubOrgMemberships ,
14+ } from "./lib/githubOrgMemberships" ;
915import { shouldScheduleGitHubProfileSync } from "./lib/githubProfileSync" ;
1016
1117export const BANNED_REAUTH_MESSAGE =
@@ -39,15 +45,34 @@ export function createGitHubAuthProvider() {
3945 return GitHub ( {
4046 clientId : process . env . AUTH_GITHUB_ID ?? "" ,
4147 clientSecret : process . env . AUTH_GITHUB_SECRET ?? "" ,
48+ authorization : {
49+ params : { scope : "read:user user:email read:org" } ,
50+ } ,
4251 // GitHub's OAuth email must not be treated as a ClawHub account key. The
4352 // immutable GitHub provider account id is the only account-linking key.
4453 allowDangerousEmailAccountLinking : false ,
45- profile ( profile ) {
54+ async profile ( profile , tokens ) {
55+ let githubOrgMembershipSync ;
56+ const accessToken = tokens . access_token ?. trim ( ) ;
57+ if ( accessToken ) {
58+ try {
59+ githubOrgMembershipSync = await fetchActiveGitHubOrgMemberships ( accessToken ) ;
60+ } catch ( error ) {
61+ console . warn (
62+ `[auth] GitHub organization membership sync failed: ${
63+ error instanceof Error ? error . message : String ( error )
64+ } `,
65+ ) ;
66+ }
67+ }
4668 return {
4769 id : normalizeGitHubProfileId ( profile . id ) ,
4870 name : profile . login ,
4971 email : profile . email ?? undefined ,
5072 image : profile . avatar_url ,
73+ ...( githubOrgMembershipSync
74+ ? { [ GITHUB_ORG_MEMBERSHIP_SYNC_PROFILE_KEY ] : githubOrgMembershipSync }
75+ : { } ) ,
5176 } ;
5277 } ,
5378 } ) ;
@@ -120,6 +145,7 @@ function userDataFromAuthProfile(args: {
120145 const {
121146 emailVerified : profileEmailVerified ,
122147 phoneVerified : profilePhoneVerified ,
148+ [ GITHUB_ORG_MEMBERSHIP_SYNC_PROFILE_KEY ] : _githubOrgMembershipSync ,
123149 ...profile
124150 } = args . profile ;
125151 const emailVerified =
@@ -187,18 +213,25 @@ export const { auth, signIn, signOut, store, isAuthenticated } = convexAuth({
187213 */
188214 async createOrUpdateUser ( ctx , args ) {
189215 const userData = userDataFromAuthProfile ( args ) ;
216+ const githubOrgMembershipSync = readGitHubOrgMembershipSync ( args . profile ) ;
190217 if ( args . existingUserId !== null ) {
191218 const userId = args . existingUserId as Id < "users" > ;
192219 const existingUser = await ctx . db . get ( userId ) ;
193220 if ( existingUser ?. deletedAt || existingUser ?. deactivatedAt ) {
194221 return userId ;
195222 }
196223 await ctx . db . patch ( userId , userData ) ;
224+ if ( githubOrgMembershipSync ) {
225+ await replaceGitHubOrgMemberships ( ctx , userId , githubOrgMembershipSync ) ;
226+ }
197227 await schedulePostUserCreatedOrUpdated ( ctx , userId , existingUser ) ;
198228 return userId ;
199229 }
200230
201231 const userId = await ctx . db . insert ( "users" , userData ) ;
232+ if ( githubOrgMembershipSync ) {
233+ await replaceGitHubOrgMemberships ( ctx , userId , githubOrgMembershipSync ) ;
234+ }
202235 const user = await ctx . db . get ( userId ) ;
203236 await schedulePostUserCreatedOrUpdated ( ctx , userId , user ) ;
204237 return userId ;
0 commit comments