diff --git a/backend/tss_api/src/middleware/discord_auth/index.ts b/backend/tss_api/src/middleware/discord_auth/index.ts index 9e6d7514e..d3e6ad5a5 100644 --- a/backend/tss_api/src/middleware/discord_auth/index.ts +++ b/backend/tss_api/src/middleware/discord_auth/index.ts @@ -39,16 +39,17 @@ export async function discordAuthMiddleware( return; } - if (!result.data.email) { + if (!result.data.id) { res.status(401).json({ - error: "Can't get email from Discord token", + error: "Can't get id from Discord token", }); return; } res.locals.oauth_user = { type: "discord" as AuthType, - email: result.data.email, + // in discord, use discord id as email with prefix + email: `discord_${result.data.id}`, name: result.data.username, }; diff --git a/backend/tss_api/src/middleware/google_auth/index.ts b/backend/tss_api/src/middleware/google_auth/index.ts index 2e072c1d6..961f26a5b 100644 --- a/backend/tss_api/src/middleware/google_auth/index.ts +++ b/backend/tss_api/src/middleware/google_auth/index.ts @@ -40,16 +40,18 @@ export async function googleAuthMiddleware( return; } - if (!result.data.email || !result.data.sub || !result.data.name) { + if (!result.data.sub || !result.data.email) { res.status(401).json({ - error: "Unauthorized: Invalid token", + error: "Can't get sub or email from Google token", }); return; } res.locals.oauth_user = { type: "google" as AuthType, - email: result.data.email, + // in google, use google sub as email with prefix + email: `google_${result.data.sub}`, + name: result.data.email, }; next(); diff --git a/backend/tss_api/src/middleware/telegram_auth/index.ts b/backend/tss_api/src/middleware/telegram_auth/index.ts index 5b7d6a4be..6db7c027f 100644 --- a/backend/tss_api/src/middleware/telegram_auth/index.ts +++ b/backend/tss_api/src/middleware/telegram_auth/index.ts @@ -54,6 +54,12 @@ export async function telegramAuthMiddleware( } const userInfo: TelegramUserInfo = result.data; + if (!userInfo.id) { + res.status(401).json({ + error: "Can't get id from Telegram token", + }); + return; + } res.locals.oauth_user = { type: "telegram" as AuthType, diff --git a/backend/tss_api/src/middleware/x_auth/index.ts b/backend/tss_api/src/middleware/x_auth/index.ts index 92b34352a..c8de151d3 100644 --- a/backend/tss_api/src/middleware/x_auth/index.ts +++ b/backend/tss_api/src/middleware/x_auth/index.ts @@ -39,9 +39,9 @@ export async function xAuthMiddleware( return; } - if (!result.data.id || !result.data.username) { + if (!result.data.id) { res.status(401).json({ - error: "Unauthorized: Invalid token", + error: "Can't get id from X token", }); return; } diff --git a/embed/oko_attached/src/window_msgs/oauth_info_pass/discord.ts b/embed/oko_attached/src/window_msgs/oauth_info_pass/discord.ts index a8fbb84fb..e2352c834 100644 --- a/embed/oko_attached/src/window_msgs/oauth_info_pass/discord.ts +++ b/embed/oko_attached/src/window_msgs/oauth_info_pass/discord.ts @@ -81,6 +81,12 @@ export async function verifyIdTokenOfDiscord( } const result = await response.json(); + if (!result.id) { + return { + success: false, + err: "Discord id not found", + }; + } const userInfo: DiscordUserInfo = { id: result.id, diff --git a/embed/oko_attached/src/window_msgs/oauth_info_pass/token.ts b/embed/oko_attached/src/window_msgs/oauth_info_pass/token.ts index 7cbaafb57..e6eb12044 100644 --- a/embed/oko_attached/src/window_msgs/oauth_info_pass/token.ts +++ b/embed/oko_attached/src/window_msgs/oauth_info_pass/token.ts @@ -32,11 +32,7 @@ export async function verifyIdToken( success: true, data: { provider: "auth0", - email: auth0TokenInfo.email, - email_verified: auth0TokenInfo.email_verified, - nonce: auth0TokenInfo.nonce, - name: auth0TokenInfo.name, - sub: auth0TokenInfo.sub, + user_identifier: auth0TokenInfo.email, }, }; } @@ -54,11 +50,8 @@ export async function verifyIdToken( success: true, data: { provider: "google", - email: googleTokenInfo.email, - email_verified: googleTokenInfo.email_verified === "true", - nonce: googleTokenInfo.nonce, - name: googleTokenInfo.name, - sub: googleTokenInfo.sub, + // in google, use google sub as user identifier with prefix + user_identifier: `google_${googleTokenInfo.sub}`, }, }; } @@ -84,8 +77,8 @@ export async function verifyIdToken( success: true, data: { provider: "discord", - email: discordTokenInfo.data.email, - name: discordTokenInfo.data.username, + // in discord, use discord id as user identifier with prefix + user_identifier: `discord_${discordTokenInfo.data.id}`, }, }; } @@ -100,20 +93,12 @@ export async function verifyIdToken( }; } - if (!xTokenInfo.data.id) { - return { - success: false, - err: "X email not found", - }; - } - return { success: true, data: { provider: "x", - // in x, use x id as email - email: xTokenInfo.data.id, - name: xTokenInfo.data.name, + // in x, use x id as user identifier with prefix + user_identifier: `x_${xTokenInfo.data.id}`, }, }; } @@ -143,10 +128,15 @@ async function verifyGoogleIdToken( } const googleTokenInfo = (await response.json()) as GoogleTokenInfo; + if (googleTokenInfo.nonce !== nonce) { throw new Error("Google token nonce mismatch"); } + if (!googleTokenInfo.sub) { + throw new Error("Google token sub not found"); + } + return googleTokenInfo; } diff --git a/embed/oko_attached/src/window_msgs/oauth_info_pass/validate_social_login.ts b/embed/oko_attached/src/window_msgs/oauth_info_pass/validate_social_login.ts index 89a040629..b5f8f9508 100644 --- a/embed/oko_attached/src/window_msgs/oauth_info_pass/validate_social_login.ts +++ b/embed/oko_attached/src/window_msgs/oauth_info_pass/validate_social_login.ts @@ -72,7 +72,7 @@ async function validateOAuthPayloadOfX( success: true, data: { idToken: tokenInfo, - userIdentifier: `x_${userInfo.email}`, + userIdentifier: userInfo.user_identifier, }, }; } @@ -136,12 +136,6 @@ async function validateOAuthPayloadOfDiscord( } const userInfo = verifyIdTokenRes.data; - if (!userInfo.email) { - return { - success: false, - err: { type: "unknown", error: "Discord email not found" }, - }; - } appState.setCodeVerifier(hostOrigin, null); @@ -149,7 +143,7 @@ async function validateOAuthPayloadOfDiscord( success: true, data: { idToken: tokenRes.data, - userIdentifier: userInfo.email, + userIdentifier: userInfo.user_identifier, }, }; } @@ -186,7 +180,7 @@ async function validateOAuthPayload( success: true, data: { idToken: payload.id_token, - userIdentifier: tokenInfo.email, + userIdentifier: tokenInfo.user_identifier, }, }; } diff --git a/embed/oko_attached/src/window_msgs/oauth_info_pass/x.ts b/embed/oko_attached/src/window_msgs/oauth_info_pass/x.ts index c52789ca3..766603b74 100644 --- a/embed/oko_attached/src/window_msgs/oauth_info_pass/x.ts +++ b/embed/oko_attached/src/window_msgs/oauth_info_pass/x.ts @@ -69,6 +69,13 @@ export async function verifyIdTokenOfX( } const result = await response.json(); + if (!result.data.id) { + return { + success: false, + err: "X id not found", + }; + } + return { success: true, data: result.data }; } catch (err: any) { return { success: false, err: err.toString() }; diff --git a/embed/oko_attached/src/window_msgs/types.ts b/embed/oko_attached/src/window_msgs/types.ts index efba69172..66591a1eb 100644 --- a/embed/oko_attached/src/window_msgs/types.ts +++ b/embed/oko_attached/src/window_msgs/types.ts @@ -58,11 +58,7 @@ export interface Auth0TokenInfo { export interface TokenInfo { provider: AuthType; - email: string; - email_verified?: boolean; - nonce?: string; - name?: string; - sub?: string; + user_identifier: string; } export interface UserSignInResult { diff --git a/key_share_node/server/src/auth/types.ts b/key_share_node/server/src/auth/types.ts index 60f16a460..d3173ac68 100644 --- a/key_share_node/server/src/auth/types.ts +++ b/key_share_node/server/src/auth/types.ts @@ -2,9 +2,7 @@ import type { AuthType } from "@oko-wallet/oko-types/auth"; export interface OAuthUser { type: AuthType; - email: string; - name?: string; - sub?: string; + user_identifier: string; } export type OAuthValidationFail = diff --git a/key_share_node/server/src/middlewares/auth.ts b/key_share_node/server/src/middlewares/auth.ts index 1f3743544..d946fa35b 100644 --- a/key_share_node/server/src/middlewares/auth.ts +++ b/key_share_node/server/src/middlewares/auth.ts @@ -50,8 +50,11 @@ type VerifyResult = data: Result; }; -export interface AuthenticatedRequest - extends Request {} +export interface AuthenticatedRequest extends Request< + any, + any, + T & OAuthBody +> {} export async function bearerTokenMiddleware( req: AuthenticatedRequest, @@ -146,19 +149,18 @@ export async function bearerTokenMiddleware( switch (result.auth_type) { case "x": { - if (!result.data.data.id || !result.data.data.username) { + if (!result.data.data.id) { const errorRes: KSNodeApiErrorResponse = { success: false, code: "UNAUTHORIZED", - msg: "Invalid token: missing required fields (id or username)", + msg: "Invalid token: missing required field (id)", }; res.status(ErrorCodeMap[errorRes.code]).json(errorRes); return; } res.locals.oauth_user = { type: result.auth_type, - email: `x_${result.data.data.id}`, - name: result.data.data.username, + user_identifier: `x_${result.data.data.id}`, }; break; } @@ -174,8 +176,7 @@ export async function bearerTokenMiddleware( } res.locals.oauth_user = { type: result.auth_type, - email: `telegram_${result.data.data.id}`, - name: result.data.data.username, + user_identifier: `telegram_${result.data.data.id}`, }; break; } @@ -191,31 +192,39 @@ export async function bearerTokenMiddleware( } res.locals.oauth_user = { type: result.auth_type, - email: result.data.data.email, - name: result.data.data.username, + user_identifier: `discord_${result.data.data.id}`, + }; + break; + } + case "google": { + if (!result.data.data.sub || !result.data.data.email) { + const errorRes: KSNodeApiErrorResponse = { + success: false, + code: "UNAUTHORIZED", + msg: "Invalid token: missing required field (sub or email)", + }; + res.status(ErrorCodeMap[errorRes.code]).json(errorRes); + return; + } + res.locals.oauth_user = { + type: result.auth_type, + user_identifier: `google_${result.data.data.sub}`, }; break; } - case "google": case "auth0": { - if ( - !result.data.data.email || - !result.data.data.sub || - !result.data.data.name - ) { + if (!result.data.data.email || !result.data.data.sub) { const errorRes: KSNodeApiErrorResponse = { success: false, code: "UNAUTHORIZED", - msg: "Invalid token: missing required fields (email, sub, or name)", + msg: "Invalid token: missing required field (email or sub)", }; res.status(ErrorCodeMap[errorRes.code]).json(errorRes); return; } res.locals.oauth_user = { type: result.auth_type, - email: result.data.data.email, - name: result.data.data.name, - sub: result.data.data.sub, + user_identifier: result.data.data.email, }; break; } diff --git a/key_share_node/server/src/routes/key_share/index.ts b/key_share_node/server/src/routes/key_share/index.ts index 13e6e8dd9..da8e8e339 100644 --- a/key_share_node/server/src/routes/key_share/index.ts +++ b/key_share_node/server/src/routes/key_share/index.ts @@ -172,7 +172,7 @@ export function makeKeyshareRouter() { const registerKeyShareRes = await registerKeyShare( state.db, { - user_auth_id: oauthUser.email, + user_auth_id: oauthUser.user_identifier, auth_type, curve_type: body.curve_type, public_key: publicKeyBytesRes.data, @@ -302,7 +302,7 @@ export function makeKeyshareRouter() { const getKeyShareRes = await getKeyShare( state.db, { - user_auth_id: oauthUser.email, + user_auth_id: oauthUser.user_identifier, auth_type, public_key: publicKeyBytesRes.data, }, @@ -569,7 +569,7 @@ export function makeKeyshareRouter() { const reshareKeyShareRes = await reshareKeyShare( state.db, { - user_auth_id: oauthUser.email, + user_auth_id: oauthUser.user_identifier, auth_type, curve_type: body.curve_type, public_key: publicKeyBytesRes.data,