MCPcopy
hub / github.com/learnhouse/learnhouse / signWithGoogle

Function signWithGoogle

apps/api/src/services/auth/utils.py:96–196  ·  view source on GitHub ↗
(
    request: Request,
    access_token: str,
    email: str,
    org_id: Optional[int] = None,
    current_user=Depends(get_current_user),
    db_session: AsyncSession = Depends(get_db_session),
)

Source from the content-addressed store, hash-verified

94
95
96async def signWithGoogle(
97 request: Request,
98 access_token: str,
99 email: str,
100 org_id: Optional[int] = None,
101 current_user=Depends(get_current_user),
102 db_session: AsyncSession = Depends(get_db_session),
103):
104 # Google
105 google_user = await get_google_user_info(access_token)
106
107 # SECURITY: trust only the email Google returns *and* explicitly marks as
108 # verified. Previously this fell back to the body-supplied ``email`` when
109 # Google omitted it (which happens whenever the access token was minted
110 # without the ``email`` scope), letting an attacker with any valid Google
111 # token impersonate any LearnHouse user whose address they knew. The body
112 # ``email`` field is kept in the request schema for backward compatibility
113 # but is no longer used for identity resolution.
114 google_email = google_user.get("email")
115 google_email_verified = google_user.get("email_verified")
116 if not google_email or not google_email_verified:
117 raise HTTPException(
118 status_code=401,
119 detail="Google did not return a verified email for this account",
120 )
121 # Normalise to lower-case to match the DB unique-ish invariant on email.
122 user_email = google_email.strip().lower()
123
124 user = (await db_session.execute(
125 select(User).where(User.email == user_email)
126 )).scalars().first()
127
128 if not user:
129 # Extract user data with safe defaults
130 given_name = google_user.get("given_name", "")
131 family_name = google_user.get("family_name", "")
132 picture = google_user.get("picture", "")
133
134 # Generate username more robustly
135 username_parts = []
136 if given_name:
137 username_parts.append(given_name)
138 if family_name:
139 username_parts.append(family_name)
140
141 # If no name parts available, use part of email
142 if not username_parts and user_email and "@" in user_email:
143 email_prefix = user_email.split("@")[0]
144 if email_prefix: # Make sure it's not empty
145 username_parts.append(email_prefix)
146
147 # If still no parts, use a default
148 if not username_parts:
149 username_parts.append("user")
150
151 username = "".join(username_parts) + str(random.randint(10, 99))
152
153 user_object = UserCreate(

Calls 11

UserCreateClass · 0.90
create_userFunction · 0.90
create_user_without_orgFunction · 0.90
get_client_ipFunction · 0.90
update_login_infoFunction · 0.90
get_google_user_infoFunction · 0.85
commitMethod · 0.80
getMethod · 0.45
firstMethod · 0.45
scalarsMethod · 0.45
executeMethod · 0.45