Skip to content

fix(auth): support comma-separated multi-scope in auth login --scope#764

Open
meijing0114 wants to merge 1 commit intolarksuite:mainfrom
meijing0114:fix/auth-login-multi-scope
Open

fix(auth): support comma-separated multi-scope in auth login --scope#764
meijing0114 wants to merge 1 commit intolarksuite:mainfrom
meijing0114:fix/auth-login-multi-scope

Conversation

@meijing0114
Copy link
Copy Markdown

@meijing0114 meijing0114 commented May 7, 2026

Bug repro

lark-cli auth login --scope "vc:note:read,vc:meeting.meetingevent:read"

fails with:

device authorization failed: The provided scope list contains invalid or malformed scopes.

A single scope (--scope "vc:note:read") works, so the comma-joined value is the trigger.

Root cause

cmd/auth/login.go reads --scope as a raw StringVar and passes it through unchanged to RequestDeviceAuthorization. OAuth 2.0 (RFC 6749 §3.3) requires the scope parameter to be a space-delimited list on the wire, so a comma-joined string is treated as one malformed scope by the auth endpoint.

The flag help advertises "space-separated" but most users (and AI agents synthesizing commands) reach for commas first because shell-quoting whitespace is awkward — and --domain already accepts , (--domain calendar,task), so the inconsistency is an easy footgun.

Fix

Normalize --scope input before sending: split on commas/whitespace, trim, dedupe (first occurrence wins, order preserved), re-join with single spaces. Implementation is a pure helper normalizeScopeInput next to the other small helpers in login.go — no behavior change for already-valid space-separated inputs.

Updated flag help string from space-separated to space- or comma-separated.

Test cases

Added TestNormalizeScopeInput covering:

  • empty input
  • single scope
  • comma-separated (the failing case)
  • space-separated (existing behavior)
  • mixed separators (comma + space + tab + newline)
  • whitespace trimming
  • duplicate elimination
  • trailing/leading/repeated separators
  • only-separator input

Existing 87 tests in cmd/auth/... all still pass.

User scenario

I keep adding new VC API endpoints to my agent workflows, and every new endpoint means another auth login to grant the scope. Composing the command via shell or AI agent, --scope "a,b" is the natural reach — with this fix it just works, instead of returning a confusing "malformed scopes" error that requires reading docs to learn the OAuth wire format.

Summary by CodeRabbit

  • New Features

    • The auth login command's --scope flag now accepts comma-, space-, or mixed-separated inputs; inputs are trimmed, empties removed, duplicates deduplicated (preserving first-seen order), and normalized to a single space-delimited scope string for device authorization.
  • Tests

    • Added unit tests covering various scope input formats, trimming, deduplication, and edge cases to ensure consistent normalization.

`lark-cli auth login --scope "a,b"` previously sent the raw comma-joined
string to the device authorization endpoint, which treats it as a single
malformed scope and fails with:

  device authorization failed: The provided scope list contains invalid
  or malformed scopes.

OAuth 2.0 (RFC 6749 §3.3) requires space-delimited scopes on the wire,
but commas are the more natural separator for users typing on a shell
(quoting whitespace is awkward, especially for AI-agent generated
commands). Accept both: split on commas/whitespace, trim, dedupe, then
re-join with single spaces.

Also adds unit tests covering single, comma, space, mixed, dedupe, and
trailing-separator inputs.
@CLAassistant
Copy link
Copy Markdown

CLAassistant commented May 7, 2026

CLA assistant check
All committers have signed the CLA.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 7, 2026

Review Change Stack
No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: cdb53ed0-2403-42ed-8269-4577acb0945c

📥 Commits

Reviewing files that changed from the base of the PR and between eb1ab99 and 9f20c8a.

📒 Files selected for processing (2)
  • cmd/auth/login.go
  • cmd/auth/login_test.go
🚧 Files skipped from review as they are similar to previous changes (2)
  • cmd/auth/login_test.go
  • cmd/auth/login.go

📝 Walkthrough

Walkthrough

The auth login command now normalizes the --scope flag to accept multiple delimiter formats (commas, spaces, tabs, or mixed) before requesting device authorization. Scopes are deduplicated while preserving first-occurrence order, trimmed, and converted to the canonical space-delimited format required by the endpoint.

Changes

Scope Normalization in Auth Login

Layer / File(s) Summary
Input Format & Help Text
cmd/auth/login.go (lines 65-67)
Help text for --scope flag updated to document comma- or space-separated value acceptance.
Normalization Implementation
cmd/auth/login.go (lines 539-571)
New normalizeScopeInput helper function parses raw scope strings using commas and whitespace as delimiters, removes empties, deduplicates (first-seen wins), and returns a canonical space-delimited scope string.
Integration
cmd/auth/login.go (lines 188-193)
authLoginRun uses normalizeScopeInput(opts.Scope) to normalize the raw scope flag before device authorization.
Tests
cmd/auth/login_test.go (lines 73-98)
TestNormalizeScopeInput covers empty input, single scopes, comma/space/tab separators, mixed delimiters, trimming, deduplication, and edge cases.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Suggested labels

size/S

Suggested reviewers

  • liangshuo-1
  • yux1a0-63

Poem

🐰 I munched through commas, tabs, and space,
I trimmed the empties without a trace,
First-seen kept its place, duplicates undone,
One single space joins scopes into one—
Hooray! The login flow hops on. 🥕✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 62.50% 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
Title check ✅ Passed The title clearly and concisely summarizes the main change: adding support for comma-separated scopes in the auth login command.
Description check ✅ Passed The description provides comprehensive coverage including bug reproduction, root cause analysis, the fix implementation, test cases, and user scenario. All template sections are well-addressed with detailed content.
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

Tip

💬 Introducing Slack Agent: The best way for teams to turn conversations into code.

Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.

  • Generate code and open pull requests
  • Plan features and break down work
  • Investigate incidents and troubleshoot customer tickets together
  • Automate recurring tasks and respond to alerts with triggers
  • Summarize progress and report instantly

Built for teams:

  • Shared memory across your entire org—no repeating context
  • Per-thread sandboxes to safely plan and execute work
  • Governance built-in—scoped access, auditability, and budget controls

One agent for your entire SDLC. Right inside Slack.

👉 Get started


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.

@github-actions github-actions Bot added the size/L Large or sensitive change across domains or core paths label May 7, 2026
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

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 current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@cmd/auth/login.go`:
- Around line 188-193: The normalized scope (finalScope) can become empty (e.g.,
input " , , ") even though the user passed --scope, so add a validation after
calling normalizeScopeInput(opts.Scope) to detect when opts.Scope is non-empty
but finalScope == "" and return a user-facing validation error; update the login
command handler (around where finalScope is set) to check opts.Scope and
finalScope and fail fast with a clear message like "invalid scope: empty after
normalization" instead of proceeding to the device authorization flow.
🪄 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: defaults

Review profile: CHILL

Plan: Pro

Run ID: c9219c9f-a010-4ea0-b66b-dc83d043338c

📥 Commits

Reviewing files that changed from the base of the PR and between 8b80810 and eb1ab99.

📒 Files selected for processing (2)
  • cmd/auth/login.go
  • cmd/auth/login_test.go

Comment thread cmd/auth/login.go
Comment on lines +188 to 193
// Normalize --scope so users can pass either OAuth-standard space-separated
// values or the more natural comma-separated list. RFC 6749 §3.3 mandates
// space-delimited scopes in the wire request, so the device authorization
// endpoint rejects raw "a,b" strings as a single malformed scope.
finalScope := normalizeScopeInput(opts.Scope)

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot May 7, 2026

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Validate normalized scope is not empty when --scope is provided.

At Line 192, normalizeScopeInput can turn inputs like " , , " into "", but the command still proceeds as if scope was provided. Add a guard right after normalization to fail fast with validation error.

Suggested patch
 finalScope := normalizeScopeInput(opts.Scope)
+if opts.Scope != "" && finalScope == "" {
+	return output.ErrValidation("please specify at least one valid scope")
+}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// Normalize --scope so users can pass either OAuth-standard space-separated
// values or the more natural comma-separated list. RFC 6749 §3.3 mandates
// space-delimited scopes in the wire request, so the device authorization
// endpoint rejects raw "a,b" strings as a single malformed scope.
finalScope := normalizeScopeInput(opts.Scope)
// Normalize --scope so users can pass either OAuth-standard space-separated
// values or the more natural comma-separated list. RFC 6749 §3.3 mandates
// space-delimited scopes in the wire request, so the device authorization
// endpoint rejects raw "a,b" strings as a single malformed scope.
finalScope := normalizeScopeInput(opts.Scope)
if opts.Scope != "" && finalScope == "" {
return output.ErrValidation("please specify at least one valid scope")
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@cmd/auth/login.go` around lines 188 - 193, The normalized scope (finalScope)
can become empty (e.g., input " , , ") even though the user passed --scope, so
add a validation after calling normalizeScopeInput(opts.Scope) to detect when
opts.Scope is non-empty but finalScope == "" and return a user-facing validation
error; update the login command handler (around where finalScope is set) to
check opts.Scope and finalScope and fail fast with a clear message like "invalid
scope: empty after normalization" instead of proceeding to the device
authorization flow.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

please check this

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

@JackZhao10086 I've checked the current code — the concern is still valid. Here's the exact scenario:

  1. A user runs lark-cli auth login --scope " , , " (separators only, no real scope tokens).
  2. hasAnyOption evaluates to true (because opts.Scope != ""), so the "no options" interactive prompt/guard is bypassed.
  3. normalizeScopeInput(" , , ") returns "".
  4. Since neither --domain nor --recommend are set, finalScope stays "".
  5. The empty string is forwarded to RequestDeviceAuthorization, likely producing a cryptic server-side error instead of a clear local validation message.

The suggested guard should be added right after normalization:

finalScope := normalizeScopeInput(opts.Scope)
if opts.Scope != "" && finalScope == "" {
    return output.ErrValidation("please specify at least one valid scope")
}

This is a minimal, targeted fix that fails fast with a user-friendly message whenever the provided --scope value collapses to nothing after normalization.


🧠 Learnings used
Learnt from: JayYoung2021
Repo: larksuite/cli PR: 410
File: cmd/auth/login_scope_cache.go:47-54
Timestamp: 2026-04-11T23:06:23.250Z
Learning: In larksuite/cli Go code, use `validate.SafeInputPath` only for user-supplied file path inputs (e.g., `--file` flags). Do NOT require `validate.SafeInputPath` for internally constructed, application-managed filesystem paths when: (1) their root directory is already validated via `validate.SafeEnvDirPath()` inside helpers like `appdir.CacheDir()`, `appdir.StateDir()`, or `appdir.LogDir()`, and (2) the filename/path components are sanitized by helpers such as `sanitizeLoginScopeCacheKey()`. In code reviews, missing `SafeInputPath` calls should not be flagged for these app-managed paths if the above safeguards are already in place.

Learnt from: JayYoung2021
Repo: larksuite/cli PR: 410
File: internal/update/update.go:147-147
Timestamp: 2026-04-11T23:06:28.717Z
Learning: In this repo’s Go code (larksuite/cli), treat `validate.SafeInputPath` as a guard for **user-supplied local file paths only**. When you build a path by joining a previously validated base directory (e.g., from `appdir.StateDir()`, `appdir.CacheDir()`, `appdir.ConfigDir()` which already validate env overrides via `validate.SafeEnvDirPath()`) with a compile-time constant filename (e.g., `"update-state.json"`, `"config.json"`), do **not** require an additional `validate.SafeInputPath` call before using `vfs.*` or `validate.AtomicWrite`. Reviewers should avoid flagging/adding redundant `validate.SafeInputPath` in these computed-path cases; only require it when the path ultimately comes from user input.

Learnt from: ViperCai
Repo: larksuite/cli PR: 450
File: shortcuts/slides/slides_create.go:50-60
Timestamp: 2026-04-14T03:13:09.459Z
Learning: When reviewing this Go codebase, do not require explicit `validate.SafeInputPath` / `validate.SafeOutputPath` calls for user-supplied paths if the code uses the `runtime.FileIO()` abstraction methods (`Stat`, `Open`, `Save`, `ResolvePath`). `runtime.FileIO()` is backed by `LocalFileIO` (in `localfileio.go`), which enforces `SafeInputPath`/`SafeOutputPath` before any filesystem access and reports violations as `fileio.PathValidationError`. Only require explicit `validate.SafeInputPath` when bypassing `runtime.FileIO()` and calling `vfs.*` or `os.*` directly with user-influenced paths.

@meijing0114 meijing0114 force-pushed the fix/auth-login-multi-scope branch from eb1ab99 to 9f20c8a Compare May 8, 2026 09:15
@JackZhao10086
Copy link
Copy Markdown
Collaborator

hi,meijing0114
Thanks a lot for taking the time to share this suggestion! 🙏
A potential issue has not been addressed, please check.

@codecov
Copy link
Copy Markdown

codecov Bot commented May 9, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 65.43%. Comparing base (8b80810) to head (9f20c8a).
⚠️ Report is 10 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main     #764      +/-   ##
==========================================
+ Coverage   65.40%   65.43%   +0.03%     
==========================================
  Files         508      509       +1     
  Lines       46795    47035     +240     
==========================================
+ Hits        30605    30779     +174     
- Misses      13548    13592      +44     
- Partials     2642     2664      +22     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 9, 2026

🚀 PR Preview Install Guide

🧰 CLI update

npm i -g https://pkg.pr.new/larksuite/cli/@larksuite/cli@9f20c8aeabfd0113b6416a9823f54a2989aaebf6

🧩 Skill update

npx skills add meijing0114/cli#fix/auth-login-multi-scope -y -g

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/L Large or sensitive change across domains or core paths

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants