{"id":25531748,"url":"https://github.com/starburst997/apple-code-sign","last_synced_at":"2026-01-20T11:30:17.770Z","repository":{"id":275536107,"uuid":"926136509","full_name":"starburst997/apple-code-sign","owner":"starburst997","description":"Code Signing for macOS as an Individual Developer without a mac","archived":false,"fork":false,"pushed_at":"2025-02-03T16:09:07.000Z","size":109,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-02-03T16:23:55.153Z","etag":null,"topics":["appstore","appstoreconnect","code-sign","code-signing","codesign","codesigning","tutorial"],"latest_commit_sha":null,"homepage":"","language":"Objective-C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/starburst997.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2025-02-02T16:35:53.000Z","updated_at":"2025-02-03T16:09:11.000Z","dependencies_parsed_at":"2025-02-10T05:15:25.467Z","dependency_job_id":null,"html_url":"https://github.com/starburst997/apple-code-sign","commit_stats":null,"previous_names":["starburst997/mac-code-sign","starburst997/apple-code-sign"],"tags_count":4,"template":true,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/starburst997%2Fapple-code-sign","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/starburst997%2Fapple-code-sign/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/starburst997%2Fapple-code-sign/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/starburst997%2Fapple-code-sign/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/starburst997","download_url":"https://codeload.github.com/starburst997/apple-code-sign/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":239763577,"owners_count":19692795,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["appstore","appstoreconnect","code-sign","code-signing","codesign","codesigning","tutorial"],"created_at":"2025-02-20T01:41:30.996Z","updated_at":"2026-01-20T11:30:17.692Z","avatar_url":"https://github.com/starburst997.png","language":"Objective-C","readme":"# apple-code-sign\n\nSample project to code-sign and publish an iOS and macOS app without owning a mac*.\n\n*\\*(we'll use a mac BUT inside Github Action)*\n\nThe following text is a copy of my blog post: [**Code Signing for Apple without a mac**](https://jd.boiv.in/post/2025/02/02/code-signing-apple.html).\n\n**TL;DR**: By using [fastlane match](https://docs.fastlane.tools/actions/match/) and [Github Action](https://github.com/features/actions) we can compile and publish a code-signed iOS / macOS app without ever using a mac in person.\n\n*(Part two of my series on code-signing / distributing apps, check [Part 1 on Windows](https://github.com/starburst997/windows-code-sign))*\n\n\u003cbr/\u003e\n\n## Enroll in the Apple Developer Program\n\nBefore you jump in, you need to enroll in the [Apple Developer Program](https://developer.apple.com/programs/enroll/) which is about $99 per year.\n\n\u003cbr/\u003e\n\n## Create Github Repository\n\nCreate a Github Repository for your project. Feel free to use this repository as a template since it already contains all the workflows files.\n\n\u003cbr/\u003e\n\n## Installing fastlane\n\nWe need to install [fastlane](https://fastlane.tools/) locally on our machine, first makes sure you have [ruby](https://www.ruby-lang.org/en/documentation/installation/#rubyinstaller) installed (personally I prefer via [WSL2](https://learn.microsoft.com/en-us/windows/wsl/install)).\n\nAlso you need to makes sure [Bundler](https://bundler.io/) is installed:\n\n```console\ngem install bundler\n```\n\nNow create a file called `Gemfile` in the root:\n\n```ruby\nsource \"https://rubygems.org\"\ngem \"fastlane\"\ngem 'fastlane-plugin-github_action', git: \"https://github.com/starburst997/fastlane-plugin-github_action\"\n```\n\nNotice that we're using my fork of [joshdholtz/fastlane-plugin-github_action](https://github.com/starburst997/fastlane-plugin-github_action), this is because the published gem is out of date and also because there was an issue preventing us to re-use the same repository for `fastlane match` again for other projects.\n\nNow run:\n\n```console\nbundle install\n```\n\n\u003cbr/\u003e\n\n## Create app in App Store Connect\n\n\u003ctable align=\"center\"\u003e\u003ctr\u003e\u003ctd\u003e\n\u003ca href=\"https://jd.boiv.in/assets/posts/2025-02-02-code-signing-apple/create_app_01.png\" target=\"_blank\"\u003e\u003cimg src=\"https://jd.boiv.in/assets/posts/2025-02-02-code-signing-apple/small/create_app_01.png\" alt=\"New App\" title=\"New App\" /\u003e\u003c/a\u003e\u003cp align=\"center\"\u003e1\u003c/p\u003e\n\u003c/td\u003e\u003ctd\u003e\n\u003ca href=\"https://jd.boiv.in/assets/posts/2025-02-02-code-signing-apple/create_app_02.png\" target=\"_blank\"\u003e\u003cimg src=\"https://jd.boiv.in/assets/posts/2025-02-02-code-signing-apple/small/create_app_02.png\" alt=\"New App Form\" title=\"New App Form\"/\u003e\u003c/a\u003e\u003cp align=\"center\"\u003e2\u003c/p\u003e\n\u003c/td\u003e\u003ctd\u003e\n\u003ca href=\"https://jd.boiv.in/assets/posts/2025-02-02-code-signing-apple/create_app_03.png\" target=\"_blank\"\u003e\u003cimg src=\"https://jd.boiv.in/assets/posts/2025-02-02-code-signing-apple/small/create_app_03.png\" alt=\"Create Bundle ID\" title=\"Create Bundle ID\"/\u003e\u003c/a\u003e\u003cp align=\"center\"\u003e3\u003c/p\u003e\n\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\n\n1. Register your app in [App Store Connect](https://appstoreconnect.apple.com/apps), click on the **(+)** button and select **New App**. You might create a single app for both platforms.\n\n2. You'll be asked to pick a **Bundle ID** which can be created in the **Apple Developer** website under the [Certificates, Identifiers \u0026 Profiles](https://developer.apple.com/account/resources/identifiers/bundleId/add/bundle) section.\n\n3. Remember it's value and pick the **Explicit** option.\n\n### Save secrets\n\nSave these 2 secrets in the github repository for your project (both equals if you registered only one app):\n\n- `IOS_BUNDLE_ID`: The iOS bundle ID\n- `MAC_BUNDLE_ID`: The macOS bundle ID\n\n\u003cbr/\u003e\n\n## Generate App Store Connect API Key\n\n\u003ctable align=\"center\"\u003e\u003ctr\u003e\u003ctd\u003e\n\u003ca href=\"https://jd.boiv.in/assets/posts/2025-02-02-code-signing-apple/api_key_01.png\" target=\"_blank\"\u003e\u003cimg src=\"https://jd.boiv.in/assets/posts/2025-02-02-code-signing-apple/small/api_key_01.png\" alt=\"New API Key\" title=\"New API Key\" /\u003e\u003c/a\u003e\u003cp align=\"center\"\u003e1\u003c/p\u003e\n\u003c/td\u003e\u003ctd\u003e\n\u003ca href=\"https://jd.boiv.in/assets/posts/2025-02-02-code-signing-apple/api_key_02.png\" target=\"_blank\"\u003e\u003cimg src=\"https://jd.boiv.in/assets/posts/2025-02-02-code-signing-apple/small/api_key_02.png\" alt=\"New API Key form\" title=\"New API Key form\"/\u003e\u003c/a\u003e\u003cp align=\"center\"\u003e2\u003c/p\u003e\n\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\n\nApp Store Connect API Key is the recomended way to sign in using fastlane.\n\nHowever if you want to also sign macOS app for individual distribution on your website, you will need to use the standard username / password procedure, this is because it requires the **Account Holder** permission to do so which is not (yet) possible with API Key. We'll discuss that in the next steps.\n\n1. Go to your [Users and Access](https://appstoreconnect.apple.com/access/integrations/api) page on [App Store Connect](https://appstoreconnect.apple.com/). Go to the **Integrations** tab and makes sure to select the section **App Store Connect API** on the left side panel and the **Team Keys** tab.\n\u003cbr/\u003e\u003cbr/\u003e\nTakes note of the **Issuer ID** value.\n\n2. Create a new Key by clicking the **(+)** button, give it a name and select the **Admin** access.\n\u003cbr/\u003e\u003cbr/\u003e\nTakes note of the **Key ID** and download the generated **P8 file** (open the file in a text editor, we will save the entire value inside a secret).\n\n*(Sadly, **Individual Keys** won't work since they are not fully compatible yet with **match** / **sigh** but that might change in the future)*\n\n### Save secrets\n\nSave these 3 secrets in the github repository for your project:\n\n- `APPSTORE_ISSUER_ID`: The **Issuer ID** from above\n- `APPSTORE_KEY_ID`: The **Key ID** from your generated API Key\n- `APPSTORE_P8`: The text content of the downloaded **P8 file**\n\n\u003cbr/\u003e\n\n## Generate Session token\n\nThis step is necessary if you need the `developer_id` certificate to sign \".app\" for individual distribution. Technically, if we use that route, we could skip the **API Key** step as well but these can still be useful, so I recommend doing both steps.\n\nSince Apple requires 2FA, saving the username / password in secrets is not enough, thankfully we can generate a **Session Token** (valid only for a short time) that we really only need once to save the certificate in the match repository (and in the future when that certificate expires).\n\nTakes note of both your Apple ID **username** and **password**.\n\nGenerate a **Session Token** using [fastlane spaceauth](https://docs.fastlane.tools/getting-started/ios/authentication/):\n\n```console\nfastlane spaceauth -u YOUR_USERNAME\n```\n\nCopy *(right-click in most terminal)* the generated value (without the `export FASTLANE_SESSION=` prefix).\n\n### Save secrets\n\nSave these 3 secrets in the github repository for your project:\n\n- `FASTLANE_USER`: Your Apple ID username\n- `FASTLANE_PASSWORD`: Your Apple ID password\n- `FASTLANE_SESSION`: The value of `fastlane spaceauth`\n\n\u003cbr/\u003e\n\n## Create the fastlane match repository\n\nThe `fastlane match` command can save all of your Apple certificates / profiles inside a private git repository for convenience and use in a CI environment.\n\nCreate a new empty **PRIVATE** github repository (any name you want).\n\n### Save secrets\n\nSave these 2 secrets in the github repository for your **project** (not the newly created one for match):\n\n- `MATCH_REPOSITORY`: Your newly created private repo (ex: `starburst997/fastlane-match`)\n- `MATCH_PASSWORD`: A unique password of your choice (save it in your password manager for re-use in other projects)\n\n\u003cbr/\u003e\n\n## Generate a Personal Access Token (PAT)\n\n\u003ctable align=\"center\"\u003e\u003ctr\u003e\u003ctd\u003e\n\u003ca href=\"https://jd.boiv.in/assets/posts/2025-02-02-code-signing-apple/pat_01.png\" target=\"_blank\"\u003e\u003cimg src=\"https://jd.boiv.in/assets/posts/2025-02-02-code-signing-apple/small/pat_01.png\" alt=\"Generate New Token (Classic)\" title=\"Generate New Token (Classic)\" /\u003e\u003c/a\u003e\u003cp align=\"center\"\u003e1\u003c/p\u003e\n\u003c/td\u003e\u003ctd\u003e\n\u003ca href=\"https://jd.boiv.in/assets/posts/2025-02-02-code-signing-apple/pat_02.png\" target=\"_blank\"\u003e\u003cimg src=\"https://jd.boiv.in/assets/posts/2025-02-02-code-signing-apple/small/pat_02.png\" alt=\"Use repo score\" title=\"Use repo score\"/\u003e\u003c/a\u003e\u003cp align=\"center\"\u003e2\u003c/p\u003e\n\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\n\nWe also need to generate a **Personal Access Token** for Github. \n\n1. Visit your [settings page](https://github.com/settings/tokens) and click on **Generate new token** and select **Generate new token (classic)**.\n\n2. We need all the **repo** scope enabled. Set **no expiration**. Click **Generate token** and save the value.\n\n### Save secrets\n\nSave this secret in the github repository for your project:\n\n- `GH_PAT`: The value of your newly generated token\n\n\u003cbr/\u003e\n\n## Additionals secrets\n\nAlso add these 3 secrets to your github repository:\n\n- `APPLE_DEVELOPER_EMAIL`: Your Apple ID\n- `APPLE_CONNECT_EMAIL`: Apple Connect email (same as above if using a single shared developer)\n- `APPLE_TEAM_ID`: Team Id from your [Apple Developer Account - Membership Details](https://developer.apple.com/account/#/membership/)\n\n\u003cbr/\u003e\n\n## Secrets reviews\n\nMakes sure you have all of these 14 secrets in your github repository:\n\n- `IOS_BUNDLE_ID`\n- `MAC_BUNDLE_ID`\n- `APPSTORE_ISSUER_ID`\n- `APPSTORE_KEY_ID`\n- `APPSTORE_P8`\n- `FASTLANE_USER`\n- `FASTLANE_PASSWORD`\n- `FASTLANE_SESSION`\n- `MATCH_REPOSITORY`\n- `MATCH_PASSWORD`\n- `GH_PAT`\n- `APPLE_DEVELOPER_EMAIL`\n- `APPLE_CONNECT_EMAIL`\n- `APPLE_TEAM_ID`\n\n*(Save those variables inside a Password Manager for re-use in future projects, except for the bundle ids, they won't change)*\n\n\u003cbr/\u003e\n\n## Create Fastfiles\n\nBy using `import_from_git` we can reference external *Fastfile* files, but feel free to copy the original instead to fit your pipeline better.\n\n#### fastlane/Appfile\n```ruby\nfor_platform :ios do\n  apple_dev_portal_id(ENV['APPLE_DEVELOPER_EMAIL'])\n  itunes_connect_id(ENV['APPLE_CONNECT_EMAIL'])\n  team_id(ENV['APPLE_TEAM_ID'])\n  itc_team_id(ENV['APPLE_TEAM_ID'])\n  app_identifier(ENV['IOS_BUNDLE_ID'])\nend\n\nfor_platform :mac do\n  apple_dev_portal_id(ENV['APPLE_DEVELOPER_EMAIL'])\n  itunes_connect_id(ENV['APPLE_CONNECT_EMAIL'])\n  team_id(ENV['APPLE_TEAM_ID'])\n  itc_team_id(ENV['APPLE_TEAM_ID'])\n  app_identifier(ENV['MAC_BUNDLE_ID'])\nend\n```\n\n#### fastlane/Fastfile ([iOS](https://github.com/starburst997/apple-code-sign/blob/v1/fastlane/iOS/Fastfile) / [macOS](https://github.com/starburst997/apple-code-sign/blob/v1/fastlane/macOS/Fastfile))\n```ruby\nimport_from_git(\n  url: \"https://github.com/starburst997/apple-code-sign.git\",\n  branch: \"v1\",\n  path: \"fastlane/iOS/Fastfile\"\n)\n\nimport_from_git(\n  url: \"https://github.com/starburst997/apple-code-sign.git\",\n  branch: \"v1\",\n  path: \"fastlane/macOS/Fastfile\"\n)\n```\n\n\u003cbr/\u003e\n\n## Create workflows\n\nBy using `workflow_call` we can simplify the workflow file by referencing an external one, but feel free to copy the original instead to fit your pipeline better.\n\nSave those inside the `.github/workflows` directory of your repository.\n\n#### apple_setup.yml ([original](https://github.com/starburst997/apple-code-sign/blob/v1/.github/workflows/apple_setup.yml))\n```yml\nname: Apple Setup\n\non: workflow_dispatch\n\njobs:\n  setup:\n    uses: starburst997/apple-code-sign/.github/workflows/apple_setup.yml@v1\n    secrets: inherit\n    with:\n      generate_macos: true\n      generate_ios: true\n      generate_appstore: true\n      generate_developer_id: true\n      use_session: true\n```\n\n#### ios.yml ([original](https://github.com/starburst997/apple-code-sign/blob/v1/.github/workflows/ios.yml))\n```yml\nname: Build iOS\n\non: \n  workflow_dispatch:\n\njobs:\n  build:\n    uses: starburst997/apple-code-sign/.github/workflows/ios.yml@v1\n    secrets: inherit\n    with:\n      project_path: iOS\n      xcodeproj_path: Test.xcodeproj\n      plist_path: Test/Info.plist\n      project_target: Test\n      version: \"2025.1\"\n      artifact: false\n```\n\n#### macos.yml ([original](https://github.com/starburst997/apple-code-sign/blob/v1/.github/workflows/macos.yml))\n```yml\nname: Build MacOS\n\non: \n  workflow_dispatch:\n\njobs:\n  build:\n    uses: starburst997/apple-code-sign/.github/workflows/macos.yml@v1\n    secrets: inherit\n    with:\n      project_path: macOS\n      xcodeproj_path: Test.xcodeproj\n      plist_path: Test/Info.plist\n      project_target: Test\n      version: \"2025.1\"\n      artifact: true\n      generate_appstore: true\n      generate_developer_id: true\n      generate_dmg: true\n```\n\nNotice that we need to specify the project's path, target, plist and version.\n\nIf you want to upload the artifact to use in your workflow (ex; upload to S3 afterward), set `artifact: true`. The artifact name for iOS is `build-ios` and for macOS is `build-macos`.\n\n\u003cbr/\u003e\n\n## Initialize fastlane match\n\nGo into the **Actions** tab of your project's github repository and run the action **Apple Setup** (disable `use_session` if you want to use **API Key**).\n\nNotice that your match repository will now be populated with the certificates and profiles for your app, it will also save the deploy key as a secret inside your repo.\n\nIn the future (in a year), you might want to run again to renew any expired certificates. The **Developer ID Application** will need to be renewed in ~5 year.\n\n\u003cbr/\u003e\n\n## Build and Distribute App\n\nNow you can manually run the action **Build iOS** and **Build Mac** to build your app and have it uploaded to Testflight. If you're satisfied with your builds, you can then use those to publish on the AppStore inside App Store Connect.\n\nThe workflow will also automatically increment the build number and save it as a variable in the repository.\n\nI've also included a [release workflow](https://github.com/starburst997/apple-code-sign/blob/main/.github/workflows/release.yml) as an example.\n\nThe macOS builds also includes an optional **.dmg** and **.app.zip** ready to be hosted, both are [notarized and stapled](https://developer.apple.com/documentation/security/notarizing-macos-software-before-distribution).\n\n\u003cbr/\u003e","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fstarburst997%2Fapple-code-sign","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fstarburst997%2Fapple-code-sign","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fstarburst997%2Fapple-code-sign/lists"}