Skip to content

fix(auth): create default token for third-party registrations - #4374

Open
iamliuyin wants to merge 3 commits into
QuantumNous:mainfrom
iamliuyin:fix/default-token-third-party-register
Open

fix(auth): create default token for third-party registrations#4374
iamliuyin wants to merge 3 commits into
QuantumNous:mainfrom
iamliuyin:fix/default-token-third-party-register

Conversation

@iamliuyin

@iamliuyin iamliuyin commented Apr 21, 2026

Copy link
Copy Markdown

Summary

  • extract default token creation into a shared helper for new user registration flows
  • create the default token for newly registered OAuth/OIDC users when GENERATE_DEFAULT_TOKEN is enabled
  • create the default token for newly registered WeChat users without creating duplicates for returning users

Test plan

  • go test ./...
  • Register a new password user with GENERATE_DEFAULT_TOKEN=true and confirm a default token is created
  • Register a new OAuth/OIDC user with GENERATE_DEFAULT_TOKEN=true and confirm a default token is created
  • Register a new WeChat user with GENERATE_DEFAULT_TOKEN=true and confirm a default token is created
  • Re-login with an existing OAuth/OIDC or WeChat user and confirm no duplicate default token is created

Summary by CodeRabbit

  • New Features

    • New users created via OAuth or WeChat now automatically receive a default token at registration.
    • Default token creation is centralized for consistent behavior across registration flows.
  • Bug Fixes

    • Improved error handling and clearer user-facing messages when default token generation or creation fails.

Ensure users created through OAuth/OIDC and WeChat registration receive the same default token as password registrations when GENERATE_DEFAULT_TOKEN is enabled.

Constraint: Keep returning users from receiving duplicate default tokens on login
Rejected: Duplicating token creation logic in each registration path | would keep behavior divergent across auth flows
Confidence: high
Scope-risk: narrow
@coderabbitai

coderabbitai Bot commented Apr 21, 2026

Copy link
Copy Markdown
Contributor

Walkthrough

findOrCreateOAuthUser now returns a created flag; handlers create a default token for newly created OAuth/WeChat users via createDefaultTokenForUser. Token-generation vs insertion failures are mapped to sentinel errors and surfaced as specific i18n API errors; Register also delegates default-token creation to the new helper.

Changes

Cohort / File(s) Summary
OAuth user creation changes
controller/oauth.go
findOrCreateOAuthUser signature changed to return (*model.User, bool, error); HandleOAuth uses the returned created flag to call default-token creation and maps sentinel errors to i18n API responses.
Default token helper & sentinel errors
controller/user.go
Added createDefaultTokenForUser(userId, username) error and package-level sentinel errors errGenerateDefaultTokenKey, errCreateDefaultToken. Register delegates default-token creation to the helper and maps errors to i18n messages.
WeChat auth flow
controller/wechat.go
WeChatAuth calls createDefaultTokenForUser after successful new-user insertion and maps sentinel errors to translated API errors on failure.

Sequence Diagram

sequenceDiagram
    participant Client as Client/OAuth Provider
    participant Handler as OAuth/WeChat Handler
    participant Finder as findOrCreateOAuthUser
    participant TokenHelper as createDefaultTokenForUser
    participant DB as Database

    Client->>Handler: Auth request (OAuth/WeChat)
    Handler->>Finder: findOrCreateOAuthUser(oauthUser, session)
    activate Finder
    Finder->>DB: Lookup or insert user
    alt new user created
        Finder-->>Handler: (*User, true, nil)
    else existing or other path
        Finder-->>Handler: (*User, false, nil) or (nil, false, err)
    end
    deactivate Finder

    alt created == true
        Handler->>TokenHelper: createDefaultTokenForUser(user.Id, user.Username)
        activate TokenHelper
        TokenHelper->>TokenHelper: generate token key
        TokenHelper->>DB: insert token
        TokenHelper-->>Handler: nil or error (sentinel)
        deactivate TokenHelper

        alt token error
            Handler-->>Client: API error (mapped i18n or raw)
        else success
            Handler->>Handler: continue status checks / respond success
        end
    else created == false
        Handler->>Handler: continue status checks / respond
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

  • Fix/pr 2900 #2998: Modifies the new-OAuth-user creation path in controller/oauth.go (related to username application during new user registration).

Poem

🐰
I dug a hole and found a key so bright,
For new OAuth friends joining in the night.
A helper bakes tokens, warm and neat,
New users hop in, with tiny feet. ✨🔑

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title accurately summarizes the main objective: creating default tokens for third-party authentication registrations (OAuth, OIDC, WeChat).
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (2)
controller/user.go (2)

119-152: Consider errors.Is for sentinel comparisons and document the partial-failure behavior.

Two small concerns with the new helper:

  1. The helper returns the sentinel values directly, so the err == errGenerateDefaultTokenKey switch at Line 234 works today. However, if a future change ever wraps these (e.g., fmt.Errorf("...: %w", errCreateDefaultToken)), the switch err comparisons in all three callers silently fall through to common.ApiError and the user sees the raw internal error. Prefer errors.Is or a switch with errors.Is guards to be forward-compatible.
  2. If token.Insert() fails, the user row has already been committed (in Register, HandleOAuth, and WeChatAuth). The caller returns an API error but the user cannot retry token creation on next login — returning users skip createDefaultTokenForUser. Consider either logging this as a recoverable condition and still completing login, or documenting that the admin must manually create a token. At minimum, common.SysLog the underlying token.Insert error before returning errCreateDefaultToken so operators can diagnose the failure.
Suggested diff
 	if err := token.Insert(); err != nil {
+		common.SysLog(fmt.Sprintf("failed to insert default token for user %d: %s", userId, err.Error()))
 		return errCreateDefaultToken
 	}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@controller/user.go` around lines 119 - 152, The createDefaultTokenForUser
helper currently returns sentinel errors directly and doesn't log the underlying
token.Insert failure; change its error handling to use errors.Is in callers by
ensuring this function wraps underlying errors (or better: return the original
error) and explicitly SysLog the token.Insert error before returning
errCreateDefaultToken so operators can diagnose failures; specifically, in
createDefaultTokenForUser (function name) call common.SysLog with the actual err
from token.Insert (and optionally wrap it) and update callers' error checks to
use errors.Is(err, errGenerateDefaultTokenKey) / errors.Is(err,
errCreateDefaultToken) rather than direct equality so future wrapping won't
break behavior.

233-243: Minor: use errors.Is and drop redundant return.

switch err works because sentinels are returned unwrapped, but switch { case errors.Is(err, errGenerateDefaultTokenKey): ... } is more idiomatic in Go and robust against future wrapping. Same applies to the identical blocks in controller/oauth.go (Lines 122-129) and controller/wechat.go (Lines 107-114).

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@controller/user.go` around lines 233 - 243, Replace the switch-on-error value
with idiomatic errors.Is checks and remove the redundant return: after calling
createDefaultTokenForUser (in controller/user.go) check if err != nil then if
errors.Is(err, errGenerateDefaultTokenKey) call common.ApiErrorI18n(c,
i18n.MsgUserDefaultTokenFailed) else if errors.Is(err, errCreateDefaultToken)
call common.ApiErrorI18n(c, i18n.MsgCreateDefaultTokenErr) else call
common.ApiError(c, err); do the same change for the identical blocks that
reference
createDefaultTokenForUser/errGenerateDefaultTokenKey/errCreateDefaultToken in
controller/oauth.go and controller/wechat.go so the code is robust to wrapped
errors and eliminate the extra return where control already exits after
responding.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@controller/wechat.go`:
- Around line 106-116: Replace the hardcoded Chinese error messages in
controller/wechat.go where createDefaultTokenForUser is handled: instead of
calling common.ApiErrorMsg for the sentinel errors errGenerateDefaultTokenKey
and errCreateDefaultToken, call common.ApiErrorI18n with the corresponding i18n
keys i18n.MsgUserDefaultTokenFailed and i18n.MsgCreateDefaultTokenErr
respectively, keeping the default branch as common.ApiError(c, err); also add
the import "github.com/QuantumNous/new-api/i18n" to the file imports so the i18n
symbols are available.

---

Nitpick comments:
In `@controller/user.go`:
- Around line 119-152: The createDefaultTokenForUser helper currently returns
sentinel errors directly and doesn't log the underlying token.Insert failure;
change its error handling to use errors.Is in callers by ensuring this function
wraps underlying errors (or better: return the original error) and explicitly
SysLog the token.Insert error before returning errCreateDefaultToken so
operators can diagnose failures; specifically, in createDefaultTokenForUser
(function name) call common.SysLog with the actual err from token.Insert (and
optionally wrap it) and update callers' error checks to use errors.Is(err,
errGenerateDefaultTokenKey) / errors.Is(err, errCreateDefaultToken) rather than
direct equality so future wrapping won't break behavior.
- Around line 233-243: Replace the switch-on-error value with idiomatic
errors.Is checks and remove the redundant return: after calling
createDefaultTokenForUser (in controller/user.go) check if err != nil then if
errors.Is(err, errGenerateDefaultTokenKey) call common.ApiErrorI18n(c,
i18n.MsgUserDefaultTokenFailed) else if errors.Is(err, errCreateDefaultToken)
call common.ApiErrorI18n(c, i18n.MsgCreateDefaultTokenErr) else call
common.ApiError(c, err); do the same change for the identical blocks that
reference
createDefaultTokenForUser/errGenerateDefaultTokenKey/errCreateDefaultToken in
controller/oauth.go and controller/wechat.go so the code is robust to wrapped
errors and eliminate the extra return where control already exits after
responding.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: f0a025bb-0693-471a-80d5-6d9e43f7088d

📥 Commits

Reviewing files that changed from the base of the PR and between f995a86 and 6eed13c.

📒 Files selected for processing (3)
  • controller/oauth.go
  • controller/user.go
  • controller/wechat.go

Comment thread controller/wechat.go
Use errors.Is for default token creation failures, log token insert errors for operators, and keep WeChat registration error messaging localized.

Constraint: Keep the PR scoped to the third-party registration token fix
Rejected: Expanding the flow to auto-retry or silently continue after token creation failure | changes product behavior beyond this bug fix
Confidence: high
Scope-risk: narrow

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
controller/oauth.go (2)

1-15: ⚠️ Potential issue | 🔴 Critical

Missing errors import breaks the build.

Lines 123 and 125 call errors.Is, but the errors package is not in the import block. The package will not compile (confirmed by golangci-lint: undefined: errors).

🛠️ Proposed fix
 import (
+	"errors"
 	"fmt"
 	"net/http"
 	"strconv"

 	"github.com/QuantumNous/new-api/common"
 	"github.com/QuantumNous/new-api/i18n"
 	"github.com/QuantumNous/new-api/model"
 	"github.com/QuantumNous/new-api/oauth"
 	"github.com/gin-contrib/sessions"
 	"github.com/gin-gonic/gin"
 	"gorm.io/gorm"
 )
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@controller/oauth.go` around lines 1 - 15, The build breaks because the errors
package is used (errors.Is called at the sites that reference it) but not
imported in the controller package; add the standard "errors" import to the
import block in controller (alongside fmt, net/http, strconv, etc.) so calls to
errors.Is compile successfully—look for the usages of errors.Is around the
OAuth-related handlers in this file to verify the fix.

120-138: ⚠️ Potential issue | 🔴 Critical

Add missing "errors" import to enable compilation.

The review's analysis of the default-token failure logic is sound: the token creation happens after user persistence, and on retry the token is never recreated since created=false. This matches password-register behavior. However, the code uses errors.Is() at lines 123 and 125 without importing the "errors" package, which will cause a compilation failure.

import (
	"errors"
	"fmt"
	"net/http"
	...
)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@controller/oauth.go` around lines 120 - 138, The code in controller/oauth.go
uses errors.Is() when checking errors returned from createDefaultTokenForUser
(referenced symbols: createDefaultTokenForUser, errGenerateDefaultTokenKey,
errCreateDefaultToken) but the "errors" package is not imported; add the
standard library import "errors" to the file's import block so the calls to
errors.Is compile successfully.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@controller/oauth.go`:
- Around line 1-15: The build breaks because the errors package is used
(errors.Is called at the sites that reference it) but not imported in the
controller package; add the standard "errors" import to the import block in
controller (alongside fmt, net/http, strconv, etc.) so calls to errors.Is
compile successfully—look for the usages of errors.Is around the OAuth-related
handlers in this file to verify the fix.
- Around line 120-138: The code in controller/oauth.go uses errors.Is() when
checking errors returned from createDefaultTokenForUser (referenced symbols:
createDefaultTokenForUser, errGenerateDefaultTokenKey, errCreateDefaultToken)
but the "errors" package is not imported; add the standard library import
"errors" to the file's import block so the calls to errors.Is compile
successfully.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: b6cb2b1f-db49-4c15-bdfe-f0b916fa29ab

📥 Commits

Reviewing files that changed from the base of the PR and between 6eed13c and fa605f4.

📒 Files selected for processing (3)
  • controller/oauth.go
  • controller/user.go
  • controller/wechat.go
🚧 Files skipped from review as they are similar to previous changes (1)
  • controller/wechat.go

Add the standard errors import required by the new errors.Is checks in the OAuth default token flow.

Constraint: Keep the follow-up scoped to the review-reported compile issue
Confidence: high
Scope-risk: narrow

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@controller/oauth.go`:
- Around line 121-133: The handler currently aborts after
createDefaultTokenForUser fails, leaving the committed user without a token;
change this to log the error instead of returning so execution continues to
setupLogin (use processLogger or common.Logger to record the err from
createDefaultTokenForUser), and also make setupLogin (or the login flow)
idempotently attempt to create a default token when a returning user has zero
tokens by calling createDefaultTokenForUser when token count == 0 (so failures
are retried on subsequent logins); update any error handling around
createDefaultTokenForUser to distinguish fatal vs non-fatal paths and ensure
created/GENERATE_DEFAULT_TOKEN logic remains consistent.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: cd2ce456-97b3-4570-bfe4-6bdc3801102b

📥 Commits

Reviewing files that changed from the base of the PR and between fa605f4 and f181a1e.

📒 Files selected for processing (1)
  • controller/oauth.go

Comment thread controller/oauth.go
Comment on lines +121 to +133
if created {
if err := createDefaultTokenForUser(user.Id, user.Username); err != nil {
switch {
case errors.Is(err, errGenerateDefaultTokenKey):
common.ApiErrorI18n(c, i18n.MsgUserDefaultTokenFailed)
case errors.Is(err, errCreateDefaultToken):
common.ApiErrorI18n(c, i18n.MsgCreateDefaultTokenErr)
default:
common.ApiError(c, err)
}
return
}
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Newly created user is left without a default token if token creation fails.

If createDefaultTokenForUser fails, the handler returns an error response, but the user row (and OAuth binding) has already been committed in step 7. On the user's next login, created will be false, so the default token creation path will never run again — that user is permanently missing their default token despite GENERATE_DEFAULT_TOKEN=true.

Consider one of:

  • Log the token-creation failure and continue to setupLogin (degraded but recoverable — user can create a token manually), or
  • Additionally trigger default-token creation on subsequent logins when the user has zero tokens, so the failure is self-healing.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@controller/oauth.go` around lines 121 - 133, The handler currently aborts
after createDefaultTokenForUser fails, leaving the committed user without a
token; change this to log the error instead of returning so execution continues
to setupLogin (use processLogger or common.Logger to record the err from
createDefaultTokenForUser), and also make setupLogin (or the login flow)
idempotently attempt to create a default token when a returning user has zero
tokens by calling createDefaultTokenForUser when token count == 0 (so failures
are retried on subsequent logins); update any error handling around
createDefaultTokenForUser to distinguish fatal vs non-fatal paths and ensure
created/GENERATE_DEFAULT_TOKEN logic remains consistent.

@Calcium-Ion
Calcium-Ion force-pushed the main branch 2 times, most recently from 51fdfc5 to 2b6f1df Compare August 30, 2026 15:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant