Skip to content

Commit 4490656

Browse files
committed
feat: add manual auth0 user linking
1 parent c2197d4 commit 4490656

File tree

1 file changed

+36
-1
lines changed

1 file changed

+36
-1
lines changed

apps/rpc/src/modules/user/user-service.ts

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ import {
1919
} from "@dotkomonline/types"
2020
import { createS3PresignedPost, slugify, getNextSemesterStart, getCurrentSemesterStart } from "@dotkomonline/utils"
2121
import { trace } from "@opentelemetry/api"
22-
import type { ManagementClient } from "auth0"
22+
import type { ManagementClient, PostIdentitiesRequestProviderEnum } from "auth0"
2323
import * as crypto from "node:crypto"
2424
import { isDevelopmentEnvironment } from "../../configuration"
2525
import { isSameDay } from "date-fns"
@@ -66,6 +66,11 @@ export interface UserService {
6666
getByProfileSlug(handle: DBHandle, profileSlug: UserProfileSlug): Promise<User>
6767
findByWorkspaceUserIds(handle: DBHandle, workspaceUserIds: string[]): Promise<User[]>
6868
findUsers(handle: DBHandle, query: UserFilterQuery, page?: Pageable): Promise<User[]>
69+
/**
70+
* This is for manually linking two logins to the same user. Sometimes the automatic script seems to fail, so we this
71+
* is a manual way of linking two users. Should not be confused with the (Google) Workspace router's `linkUser`.
72+
*/
73+
linkUsers(handle: DBHandle, primaryUserId: UserId, secondaryUserId: UserId): Promise<User>
6974

7075
/**
7176
* Attempt to discover an automatically granted membership from FEIDE.
@@ -493,6 +498,36 @@ export function getUserService(
493498
return identity?.access_token ?? null
494499
},
495500

501+
async linkUsers(handle, primaryUserId, secondaryUserId) {
502+
logger.info(
503+
"Linking authentication identities for survivor User(ID=%s) and consumed User(ID=%s)",
504+
primaryUserId,
505+
secondaryUserId
506+
)
507+
508+
const primaryUser = await managementClient.users.get({ id: primaryUserId })
509+
const secondaryUser = await managementClient.users.get({ id: secondaryUserId })
510+
511+
const secondaryIdentity =
512+
secondaryUser.data.identities.find((identity) => secondaryUserId.endsWith(identity.user_id)) ||
513+
secondaryUser.data.identities[0]
514+
515+
const secondaryIdentityProvider = secondaryIdentity.provider as PostIdentitiesRequestProviderEnum
516+
517+
await managementClient.users.link(
518+
{
519+
id: primaryUser.data.user_id,
520+
},
521+
{
522+
provider: secondaryIdentityProvider, // usually "oauth2"
523+
user_id: secondaryIdentity.user_id,
524+
connection_id: secondaryIdentity.connection,
525+
}
526+
)
527+
528+
logger.info("Successfully linked identities for survivor User(ID=%s) and consumed User(ID=%s)")
529+
},
530+
496531
async createFileUpload(handle, filename, contentType, userId, createdByUserId) {
497532
const user = await this.getById(handle, userId)
498533

0 commit comments

Comments
 (0)