Skip to content

GetStoredToken swallows storage/decryption errors and reports credentials as missing #1925

Description

@yyd310

Summary

GetStoredToken currently converts every credential-storage or decoding error
into a nil token. As a result, a stored user credential can be reported as
missing when the actual problem is that the process cannot access the macOS
Keychain-backed master key, decryption failed, or the stored JSON is malformed.

In a headless/background process this surfaced as:

  • lark-cli auth status --json --verify reporting the user identity as
    missing
  • user-authenticated commands failing with token_missing

The encrypted credential file still existed and was valid. The credential was
not absent; its master key was unavailable to that process.

Environment

  • macOS 12.7.6, Intel x64
  • Observed with @larksuite/cli 1.0.70
  • The relevant implementation is unchanged in the current v1.0.71 release
  • Reproduced in fresh non-GUI/background processes, including a launchd
    process and agent/automation runners

Reproduction context

These steps describe the original failure. The affected machine has since
applied the supported workaround below and was not reverted solely to reproduce
the failure again.

  1. Log in interactively using the default macOS Keychain-backed credential
    storage.

  2. Confirm that lark-cli auth status --verify reports the user as ready.

  3. Confirm that the encrypted credential file exists under
    ~/Library/Application Support/lark-cli/ with restrictive permissions.

  4. Start a fresh headless/background process in a context that cannot access
    the macOS Keychain.

  5. Run:

    lark-cli auth status --json --verify

    or another command requiring user authentication.

Actual behavior

The CLI reports the stored user credential as missing and downstream commands
return token_missing.

Expected behavior

The CLI should distinguish at least these cases:

  • No stored credential exists
  • macOS Keychain is unavailable or access is denied
  • Credential decryption fails
  • Stored credential JSON is malformed or corrupted

Only the first case should be reported as missing.

Root cause

In v1.0.71, GetStoredToken
returns nil for both any keychain.Get error and any json.Unmarshal error:

jsonStr, err := keychain.Get(keychain.LarkCliService, accountKey(appId, userOpenId))
if err != nil || jsonStr == "" {
    return nil
}
var token StoredUAToken
if err := json.Unmarshal([]byte(jsonStr), &token); err != nil {
    return nil
}

This collapses not-found, operational, decryption, and corruption errors into
the same downstream missing result.

Issue #1038 and PR #1085 already cover the underlying macOS automation/Keychain
compatibility problem and provide config keychain-downgrade. This issue is
specifically about preserving and reporting the real storage error instead of
misclassifying it as a missing credential.

Suggested fix

  • Return a distinct not-found result only when the credential truly does not
    exist.

  • Propagate or classify Keychain, decryption, and JSON-decoding errors.

  • Do not map non-missing storage errors to user.status=missing or
    token_missing.

  • Include the existing recovery hint for affected headless environments:

    lark-cli config keychain-downgrade
  • Never include tokens, decrypted credential content, or key material in logs
    or error messages.

Suggested tests

Add automated coverage for:

  • Credential file absent: reports missing
  • Keychain retrieval denied/unavailable: reports a Keychain/storage error
  • Decryption failure: reports a decryption/corruption error
  • Malformed stored JSON: reports a decoding/corruption error
  • Headless/background execution with the supported file-backed master-key mode
  • Verification that errors and logs never expose token or key material

Workaround verified

Running the supported command below moves master-key access to the file-backed
mode:

lark-cli config keychain-downgrade

After applying it, authentication succeeded from multiple fresh background
processes and a launchd process, and user-authenticated API commands worked
without another OAuth login.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingdomain/authAuthentication subsystemdomain/coreCLI framework and core libraries

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions