auth: write JSON credential format and migrate legacy plaintext#155
Conversation
277c06a to
8c47844
Compare
somanshreddy
left a comment
There was a problem hiding this comment.
Two review notes:
- Blocking: preserving the existing
oauthblock meansheygen auth logincan save a new API key but subsequent commands may still select the preserved OAuth access token first. The resolver prefersoauth.access_tokenoverapi_key, but the client still treats the resolved string as an API key and always sends it asx-api-key(internal/client/client.go:78). So a credentials file with both a valid API key and a fresh OAuth token will select the OAuth token, then send it in the API-key header instead ofAuthorization: Bearer ....
Unless the API explicitly accepts OAuth access tokens in x-api-key, this breaks auth for the shared JSON format. Until the HTTP client supports typed credentials/Bearer auth, heygen-cli should prefer api_key here or avoid preserving/selecting OAuth in a way that changes the effective credential.
- Non-blocking compatibility concern:
FileCredentialResolver.Resolve()migrates legacy plaintext credentials to JSON as a side effect of any authenticated command, not only when the user explicitly updates auth state.
Example scenario:
- User has an older heygen-cli installed, with
~/.heygen/credentialscontaining plaintext:hg_abc123. - User runs this PR's CLI once, e.g.
heygen video list. Resolve()reads the plaintext key successfully, but also rewrites the file to{ "api_key": "hg_abc123" }.- User later rolls back to the previous heygen-cli version, runs an older binary from a script/CI image, or otherwise uses a client that only understands plaintext.
- That older client reads the whole JSON document as the API key and sends it as
x-api-key, so auth fails.
The new CLI can already read plaintext without migrating it, so read-time migration is not required for compatibility. If one-way migration is acceptable, this is fine, but it is worth making explicit. Otherwise, consider migrating only on explicit writes like heygen auth login, or behind a deliberate upgrade path.
112b17e to
a4f902f
Compare
|
Thanks @somanshreddy — both addressed. Force-pushed (signed/verified). 1. Blocking — OAuth token mis-sent as
2. Non-blocking — read-time migration rollback risk. Good catch on the mixed-version/rollback scenario. Switched to write-only migration: Also from a self-review pass on this PR: All |
somanshreddy
left a comment
There was a problem hiding this comment.
Looks good after the updates. The final stacked diff now keeps Resolve() aligned with the current HTTP client behavior: api_key is the only selected credential, OAuth-only files fail with an actionable error, and preserved OAuth blocks are only round-tripped for the other CLI. The legacy plaintext read path is also side-effect-free now, with JSON migration limited to explicit writes.
Verified locally:
go test ./internal/auth/... ./internal/client/... ./cmd/heygengo test ./...
heygen-cli now writes the shared ~/.heygen/credentials file in the JSON
format (matching hyperframes-CLI) instead of single-line plaintext, and
upgrades a legacy plaintext file to JSON in place on read.
- FileCredentialStore.Save writes `{ "api_key": "..." }` and preserves a
co-located oauth block, so saving an API key no longer clobbers an
active OAuth session written by hyperframes-CLI.
- FileCredentialResolver upgrades a legacy plaintext file to JSON on
read (best-effort: never changes the returned value, never fails the
read on a read-only FS / concurrent writer).
- Shared file-format helpers (parse + atomic 0600 write) extracted to
credentials_file.go so the store and resolver agree on the format.
Read-side compat from the parent PR is unchanged; this completes the
round-trip so both CLIs read AND write the same format.
a4f902f to
a68e4b2
Compare
Description
Completes the credential-format round-trip started in #154. That PR
taught heygen-cli to read the new JSON format; this one makes it
write JSON too and auto-upgrade a legacy plaintext file in place.
Stacked on #154 (base =
05-26-auth_read_json_credential_format).What changes:
FileCredentialStore.Savenow writes{ "api_key": "..." }(JSON,mode 0600, atomic temp+rename) instead of single-line plaintext. It
reads the existing file first and preserves a co-located
oauthblock, so
heygen auth loginno longer clobbers an active OAuthsession that hyperframes-CLI wrote. (Previously a plaintext overwrite
would silently drop the
oauthdata.)FileCredentialResolver.Resolveupgrades a legacy plaintext file toJSON on read, best-effort: it never changes the value returned and
never fails the read if the write can't happen (read-only FS,
concurrent writer). A read-only environment just leaves the file
plaintext until the next successful write.
loadCredentialsFile(parse) andwriteCredentialsFile(atomic 0600 write) — extracted to a newcredentials_file.goso the store and resolver agree on one format.Net effect: both CLIs now read and write the same
~/.heygen/credentialsJSON file, and existing plaintext files migrateforward automatically the first time either tool touches them.
Why a separate PR: #154 was scoped to read-side compat; this is a
write-side behavior change (with the OAuth-preservation data-safety
fix), so it gets its own focused review per our one-PR-per-scope
convention.
Testing
go test ./internal/auth/...green: new tests cover JSON write,OAuth-block preservation on api-key save, legacy→JSON upgrade on save,
and legacy→JSON migration on read (with a re-resolve from the upgraded
file).
cmd/heygen/auth_test.goandinternal/auth/file_store_test.goassertions from plaintext to JSON.
go vet+gofmtclean. Fullgo test ./...green.Note: a few
cmd/heygentests (TestVideoList_AuthMissing,TestVideoDownload_AuthRequired,TestAuthStatus_NoKey,TestEnrichAuthHint_ExistingHint_Preserved) fail only whenHEYGEN_API_KEYis exported in the shell — they assume no ambient key.They pass with the var unset and are unaffected by this change (they
fail the same way on
main).