Repository navigation
feat: surface sign-in failures + add release-please automation - #1
Conversation
Greptile SummaryThis PR surfaces sign-in failures to the renderer via a new
Confidence Score: 5/5Safe to merge; the auth-error broadcast is cleanly isolated and the token-safety invariant is preserved across all new paths. The core changes — auth-error surfacing,
Important Files Changed
|
Mirror the authkit-nextjs release setup: a release-please workflow that opens/maintains a release PR and, on merge, calls a reusable release workflow to publish the scoped public package to npm with provenance. Also add conventional-commit PR-title linting. - .github/workflows/release-please.yml: release-please-action + GitHub App token, triggers publish on release_created - .github/workflows/release.yml: pnpm publish --access=public --provenance - .github/workflows/lint-pr-title.yml: semantic PR title check - release-please-config.json: release-type "node", "." package - .release-please-manifest.json: pinned at 0.0.0 (first release computes the version from conventional commits) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JT8sJBpwfAuRYKP7Lk53Hh
A denied/cancelled sign-in or a failed code exchange previously only
logged to console; the renderer never learned of it and stayed silently
signed out. Add an auth-error broadcast path so consumers can react.
- new SDK-owned IPC channel `authkit:auth-error` (main -> renderer)
- AuthErrorPayload type carrying only a safe { code, message } — no
tokens; refresh-token confinement is unchanged
- broadcastAuthError() mirrors broadcastAuthChange(); createAuthKit emits
it on a callback `error` param and on a failed completeCallback
- preload bridge exposes onAuthError(); AuthKitProvider tracks it and
surfaces `error` on useAuth(), cleared on the next successful sign-in
- exported AuthErrorPayload from the root, /react and /preload entries;
broadcastAuthError from /internals
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JT8sJBpwfAuRYKP7Lk53Hh
Housekeeping ahead of the first release; no runtime behavior change. - remove leftover "Phase 1/2/3/4" roadmap wording from shipped source and spec comments (neutral wording instead) - .oxfmtrc.json: drop the stale `docs/` ignore (no docs/ dir exists) - package.json: bump engines.node to >=22.11.0 to match the authkit house style and what CI actually runs (Node 22) - README: document the new useAuth().error field and the auth-error failure-surfacing behavior Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JT8sJBpwfAuRYKP7Lk53Hh
Add bump-minor-pre-major so breaking changes bump the minor version while < 1.0.0 instead of going to 1.0.0, matching the authkit-session and authkit-tanstack-start SDK configs. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JT8sJBpwfAuRYKP7Lk53Hh
e0255e3 to
e20149b
Compare
The e2e helper hard-coded the __authkit_electron bridge global as a dotted property access inside a Playwright evaluate callback, which tripped oxlint's no-underscore-dangle rule. Import AUTHKIT_BRIDGE_KEY from src/shared/ipc-channels.js and pass it into evaluate as an argument with bracket access, matching the single-shared-constant convention established in 574f7e3. No runtime behavior change.
oxlint exits 0 on warnings by default, so CI's `pnpm run lint` let the no-underscore-dangle warning fixed in 81d881e pass unnoticed. Add --deny-warnings so any warning fails the build instead of silently accumulating.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JT8sJBpwfAuRYKP7Lk53Hh
When the sign-in ceremony fails to open (e.g. win.loadURL() rejects
because the auth server is unreachable), the failure only rejected the
renderer's signIn() promise — it never reached the auth-error broadcast,
so useAuth().error stayed empty while every other failure mode (consent
denied, window closed, failed code exchange) populated it.
The sign-in IPC handler now broadcasts the same safe { code, message }
payload on failure AND still returns { ok: false }, so signIn() keeps
throwing (backwards-compatible) while useAuth().error is populated.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JT8sJBpwfAuRYKP7Lk53Hh
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JT8sJBpwfAuRYKP7Lk53Hh
Requested by Nick Nisi · Slack thread
A DX/correctness pass plus release automation for
@workos/authkit-electron, ahead of its first publish.Before / After
Sign-in failures (the headline change). Today, if a user denies the consent screen, closes the in-app sign-in window, or the authorization-code exchange fails, the callback completes with nothing to exchange — the SDK logs to the console and the renderer is left silently signed out, with no way to tell a failed attempt from "not signed in yet." A developer building a sign-in screen had no hook to show "Sign-in failed, try again."
After this change, every such failure is broadcast to the renderer as a safe
{ code, message }payload (never tokens). It surfaces as a newerrorfield onuseAuth():errorclears automatically on the next successful sign-in.Sturdier
registerProtocol(). Calling it more than once (easy to do across re-inits or HMR) previously wired a second set ofopen-url/second-instancelisteners and leaked the first, so a single callback could be handled twice. It is now idempotent — the listeners are wired exactly once, and the JSDoc that wrongly claimed it "returns the deep-link cleanup" now matches itsvoidreturn.No more double failure signal. When the in-app auth window fails to load its page, the thrown error is now the single failure signal; the window-close handler no longer also emits a synthetic
window_closedcallback.Cleaner release story. The package can now be cut and published with the same automation the rest of the AuthKit SDKs use, instead of having no release path at all (version was pinned at
0.0.0with no changesets/release tooling).How
authkit:auth-error(main → renderer) carries anAuthErrorPayload({ code, message }only).broadcastAuthError()mirrors the existingbroadcastAuthChange()chokepoint, so the refresh-token confinement is untouched — no tokens cross this channel.createAuthKit()emits an auth-error on a callbackerrorparam (including the window ceremony'swindow_closedcancellation) and on a failedcompleteCallback(state verification or code exchange).onAuthError();AuthKitProvidersubscribes to it, exposeserrorvia context, and clears it on the next successful auth change.AuthErrorPayloadis exported from the root,/react, and/preloadentries;broadcastAuthErrorfrom/internals.registerProtocol()guards on an internalprotocolRegisteredflag thatcleanup()resets.registerProtocolidempotency, the preloadonAuthErrorsubscription, and theuseAuth().errorsurface + clear-on-success. Full suite: 136 tests, 15 files, green.Release tooling
Mirrors
authkit-nextjsexactly:.github/workflows/release-please.yml— runs release-please on pushes tomain, opening/maintaining a release PR; on merge it triggers the publish job..github/workflows/release.yml— reusable workflow that runspnpm publish --access=public --provenance(correct for the scoped public@workos/...package; provenance via OIDCid-token: write)..github/workflows/lint-pr-title.yml— conventional-commit PR-title lint (commits in this PR already follow the convention).release-please-config.json—release-type: node, single"."package..release-please-manifest.json— pinned at0.0.0; the first release computes the version from the conventional commits since.First-release steps a maintainer must do (these are why this is a draft):
release-please.ymlusesvars.SDK_BOT_APP_ID+secrets.SDK_BOT_PRIVATE_KEY(the same appauthkit-nextjsuses). Confirm that app is installed on this repo, or swap in another token source.--provenance,id-token: write). Configure npm trusted publishing for@workos/authkit-electron, or add anNPM_TOKEN/NODE_AUTH_TOKENsecret and a registry-auth step. (authkit-nextjsdoes not setNODE_AUTH_TOKENexplicitly, so it appears to use trusted publishing — confirm this matches the org's npm setup.)feat:will count) drives the initial version release-please proposes.Follow-ups (not done here — low risk, but out of scope for a tight diff)
getAccessTokenruns a full validate/refresh (src/main/session-manager.ts): it delegates togetUser()(decrypt → validateAndRefresh → persist). Left as-is on purpose — that is the correct "refresh-on-read" guarantee, and trimming it risks returning a stale/expired token. Revisit only if profiling shows the extra refresh round-trips matter.socket-tier1-analysis.yml(Socket reachability scan) exists inauthkit-nextjsbut was not ported: it requires the org-levelsecrets.SOCKET_API_KEY, which this task can't assume is provisioned for this repo. Add it separately once that secret is confirmed available.Open questions (need a human/product decision — intentionally not changed)
@workos/authkit-electron(like@workos/authkit-session), whereas the framework SDKs use@workos-inc/.... Left unchanged — confirm the intended scope before first publish, since it affects the publish config and trusted-publishing setup.switchToOrganizationwhile signed out. When called with no session it returns{ user: null }, and the IPC handler then broadcasts a signed-out payload — which could sign other windows out. Possibly fine, possibly surprising; left as-is pending a product call.as unknown as WorkOS/apiKey: ''widening at the authkit-session boundary (src/main/config.ts). Deliberate and documented; the real fix is upstream (authkit-sessionaccepting aPublicWorkOS-compatible client and an optionalapiKey). Left untouched — tracking as an upstream follow-up.🤖 Generated with Claude Code
https://claude.ai/code/session_01JT8sJBpwfAuRYKP7Lk53Hh
Generated by Claude Code