fix(client+server): OAuth login path now surfaces user identity in desktop TitleBar

Root cause of the recurring "I don't see the logged-in user info in the
desktop client" complaint: the credentials-login path builds an mcpAuth
record with email / displayName / role from the mcp-server /api/auth/login
response and the TitleBar UserPill renders fine. But the OAuth-login path
(the typical browser-redirect flow) only received an sk- API key in the
callback query string — no user fields. So:

  status.user                   == null
  UserPill: if (!user) return null
  → blank space where the user pill should be.

Fix on backend (heicode_oauth.go HeicodeOAuthAuthorize):
- After issuing the sk- token, load the authenticated user from the
  session and embed email / name / role (root|admin|user) / channel_id /
  user_id as query params on the redirect URI.

Fix on client (cc-haha/src/server/api/heicode-auth.ts handleOAuthCallback):
- Read those query params (pickUserFromQuery), build an mcpAuth record
  (buildMcpAuthFromOAuthQuery), and pass it through loginAndActivate the
  same way the credentials path does. The accessToken slot holds the sk-
  key as a placeholder — OAuth flow doesn't deliver a refreshable JWT
  pair, and this mcpAuth exists purely to surface identity on the
  TitleBar.

After this, OAuth-route users see the same gradient-avatar pill with
their email / name / role badge that credentials-route users already see.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-11 20:44:33 +08:00
co-authored by Claude Opus 4.7
parent b91a68fe2b
commit a2deeb61b0
2 changed files with 99 additions and 2 deletions
+32
View File
@@ -85,6 +85,38 @@ func HeicodeOAuthAuthorize(c *gin.Context) {
if providerID != "" {
q.Set("provider_id", providerID)
}
// Include the authenticated user's identity so the desktop client can
// display it in the title bar / settings without making a separate
// /api/user/self call (that endpoint requires a session cookie which the
// desktop client doesn't have). This is the missing piece that left the
// UserPill empty for OAuth-route logins.
var user model.User
if dbErr := model.DB.First(&user, userID).Error; dbErr == nil {
if email := strings.TrimSpace(user.Email); email != "" {
q.Set("email", email)
}
display := strings.TrimSpace(user.DisplayName)
if display == "" {
display = strings.TrimSpace(user.Username)
}
if display != "" {
q.Set("name", display)
}
switch {
case user.Role >= 100:
q.Set("role", "root")
case user.Role >= 10:
q.Set("role", "admin")
default:
q.Set("role", "user")
}
if g := strings.TrimSpace(user.Group); g != "" {
q.Set("channel_id", g)
}
q.Set("user_id", fmt.Sprintf("%d", userID))
}
parsed.RawQuery = q.Encode()
c.Redirect(http.StatusFound, parsed.String())
}