Skip to content

feat(cli): init apns --create-key creates the APNs key with the Apple ID - #1989

Closed
ArnabChatterjee20k wants to merge 3 commits into
messaging-provider-cli-apnsfrom
messaging-provider-cli-apns-create-key
Closed

ArnabChatterjee20k wants to merge 3 commits into
messaging-provider-cli-apnsfrom
messaging-provider-cli-apns-create-key

Conversation

@ArnabChatterjee20k

Copy link
Copy Markdown
Member

Stacked on #1963 (init apns).

What

appwrite init apns --create-key signs in to the Apple Developer portal with the developer's Apple ID and creates a team-scoped APNs key, so the developer never visits the portal. The same option also appears in the "How would you like to provide the APNs auth key?" prompt. Marked experimental.

How

Apple has no public API for APNs keys. The CLI runs a small Node script on top of @expo/apple-utils 2.2.1 (MIT), the library eas-cli uses for the same job (pushKey.ts).

  • internal/apple embeds helper.js, package.json and package-lock.json with go:embed.
  • On first use it checks for Node.js 18 or later, writes the files to ~/.appwrite/apple/ and runs npm ci --ignore-scripts. The lockfile pins the exact package hash. It reinstalls only when the embedded files change.
  • The script runs with the terminal attached, so apple-utils asks for the Apple ID, password and two-factor code itself. It does Auth.loginAsync({ teamId }), then Keys.createKeyAsync(context, { name, isApns: true }) and Keys.downloadKeyAsync. authState.context is the request context, as in eas-cli's getRequestContext.
  • apple-utils logs to stdout, so the result goes to a 0600 file in a private temp folder rather than stdout.
  • EXPO_NO_KEYCHAIN=1 keeps the Apple password out of the macOS Keychain. The password goes only to Apple. apple-utils caches the session cookie in ~/.app-store/, shared with eas-cli, so a rerun skips two-factor.

In init apns:

  • The .p8 is saved as AuthKey_<ID>.p8 in the project folder (mode 0600, never overwriting) before anything else, because Apple allows one download. The git-ignore warning applies as usual.
  • Then the existing flow runs: key validation, both providers, Xcode edits.
  • When Node.js is missing or old, npm fails, or sign-in fails, the CLI warns and offers the browser and file options.
  • When the team already has the maximum number of keys (MaxKeysCreatedError), it lists the team's keys, links the portal's key list and stops, asking for --key-path. Revoking from the CLI is left for a later PR.
  • --create-key and --key-path are mutually exclusive. When both providers already exist, a rerun reports "already set up" unless --force, so it never spends another key slot.

Testing

  • internal/apple: Node version check, result decoding, and an end-to-end run with stand-in node/npm (installs once, passes EXPO_NO_KEYCHAIN=1, reads the result).
  • internal/cmd: creates and saves the key and both providers, offers it from the prompt, falls back when the helper cannot run, and stops on a full team.
  • Manual: npm ci of the embedded lockfile, and running the helper without a terminal reaches apple-utils' login and fails cleanly with a readable error.
  • Not yet tested against a real Apple account.

Later

  • Revoke a key from the CLI after an explicit confirmation.
  • Topic-specific keys (one bundle ID and environment, 200 per environment), once the portal request is known.

…loper portal

Apple has no public API for APNs keys. The helper runs @expo/apple-utils
2.2.1 (MIT), the library eas-cli uses for the same job, from a small Node
script embedded in the binary. It is installed into ~/.appwrite/apple with
npm ci --ignore-scripts against a pinned lockfile, needs Node.js 18 or later,
and keeps the Apple password out of the Keychain.
--create-key, or the new prompt option, signs in to the Apple Developer
portal and creates a team-scoped APNs key. The .p8 is saved into the
project folder right away, since Apple allows one download. When Node.js
is missing or the sign-in fails, the browser and file options remain.
When the team has no free key slot, the existing keys are listed and the
command stops, asking for --key-path. Marked experimental.
@hansi-codes

hansi-codes Bot commented Oct 9, 2026 •

Copy link
Copy Markdown

🟢 Tier S · Ready to merge

Adds an experimental init apns --create-key flow that uses an embedded Node helper to sign in to Apple, create a team-scoped APNs key, and save it before configuring providers. When no team ID is already known, the sign-in flow can select the team and the CLI uses that selected team for provider setup; errors continue to fall back to the existing key-provisioning options.

Latest changes: The latest commits let Apple sign-in choose a team when no team ID is known, then carry the selected team through key saving and APNs provider setup.

Verdict New comments Fixed Still open
💬 Commented 0 0 0

Note

Not approving while a bug finding is open: Reject --key-id with --create-key

📂 Walkthrough · 8
File Change
src/SDK/Language/CLI.php Registers the embedded Apple helper assets in CLI generation.
templates/cli/internal/apple/apple.go Embeds and installs the helper, checks Node.js, runs it, and decodes created-key results.
templates/cli/internal/apple/apple_test.go Tests Node handling, result decoding, and helper subprocess integration.
templates/cli/internal/apple/helper/helper.js Signs in to Apple and creates, downloads, and returns an APNs key.
templates/cli/internal/apple/helper/package.json Declares the pinned Apple utility dependency and Node requirement.
templates/cli/internal/apple/helper/package-lock.json Locks the Apple utility dependency and package integrity hashes.
templates/cli/internal/cmd/initpush.go Adds automatic key creation, fallback handling, secure key-file saving, and team selection from sign-in.
templates/cli/internal/cmd/initpush_test.go Covers automatic creation, prompting, fallback, maximum-key handling, and sign-in-selected teams.

Reviewed the commits since d2180bd · Details · Comment @hansi-codes review to re-run, or mention @hansi-codes with a question.

@hansi-codes hansi-codes Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔵 Tier A · See the inline comments. Summary

Comment thread templates/cli/internal/cmd/initpush.go
A project without DEVELOPMENT_TEAM made init apns ask for the team ID
before offering the Apple sign-in, which already knows the account's
teams. The team question now waits until the key comes from a file or
the browser; signing in picks the team, and apple-utils asks which one
when the account has several.

@hansi-codes hansi-codes Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔵 Tier A · See the inline comments. Summary

Comment thread templates/cli/internal/apple/apple.go
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