Skip to content

feat: shared OAuth client behind access key, login/logout commands - #20

Merged
djachenko merged 5 commits into
masterfrom
feat/26.07.24.oauth_builtin_client
Jul 28, 2026
Merged

feat: shared OAuth client behind access key, login/logout commands#20
djachenko merged 5 commits into
masterfrom
feat/26.07.24.oauth_builtin_client

Conversation

@djachenko

Copy link
Copy Markdown
Owner

What

Two ways to authorize goodoc:

Path How Client
Own Cloud project (default) first-run wizard ~/.config/goodoc/credentials.json
Author's shared client goodoc login --key <KEY> client.py

Plus login / logout commands.

The access key is the client secret

Google's token endpoint rejects this client without a secret — measured, not assumed:

without client_secret -> {"error": "invalid_request", "client_secret is missing."}
with    client_secret -> {"error": "invalid_grant",   "Malformed auth code."}

Since the secret has to reach the user anyway, the key handed out is the secret. The repository ships only CLIENT_ID (public by nature — it appears in every authorization URL) and a sha256 of the key. So the secret never enters git history, and the gate is real rather than decorative: without the key the shared client cannot be used, however carefully the sources are read. The hash exists only to fail fast instead of sending the user through the browser with a bad key.

Already-authorized users are unaffected: token.json carries client id, secret and refresh token, so refreshing never touches client.py.

Shared client limits

Production without verification — no whitelist, but a cap of 100 authorizations for the lifetime of the project, which cannot be reset. Only verification lifts it, and verification requires a domain. Hence the key, and hence "own project" being the default.

Commands became a group

Adding commands turns the app into a Click group, where a variadic argument on the callback swallows the command name — goodoc login gets read as a file path. upload is now a real command, and DefaultCommandGroup inserts it when the first argument is neither a known command nor an option. goodoc file.docx keeps working, so the Automator Quick Action (goodoc "$@") needs no change. This also moves --no-open out of the global options, where it did not belong.

Checks

44 passed, ruff and mypy clean.

The author maintains a shared Google Cloud client as an alternative to
setting up your own project. It is gated behind an access key, which is
the client secret itself: the repository ships only the client id and a
sha256 of the key.

Google's token endpoint rejects this client without a secret, so the gate
is real rather than decorative — the shared client cannot be used without
the key, no matter what the sources reveal. The hash only allows failing
fast instead of sending the user through the browser with a bad key.

The first-run wizard now always sets up the user's own Cloud project;
the shared client is reachable only via `goodoc login --key`.
`login` authorizes without uploading anything and accepts `--key` for the
shared client; `logout` drops the stored token.

Adding commands turns the app into a Click group, where a variadic
argument on the callback swallows the command name — `goodoc login` would
be read as a file path. `upload` is therefore a real command, and
DefaultCommandGroup inserts it when the first argument is neither a known
command nor an option. This keeps `goodoc file.docx` working, so the
Automator Quick Action needs no change.
The shared client runs in production without verification: no whitelist,
but a permanent cap of 100 authorizations that only verification lifts,
and verification needs a domain.
CI installs linters unpinned, so ruff 0.16 broke the build the day it
shipped by widening the default rule set. Six of the nine findings are
present on master as well, so this is drift rather than a regression.

Pin is temporary — raising it is tracked in the backlog.
@djachenko
djachenko merged commit 8cac957 into master Jul 28, 2026
16 checks passed
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