# App Store Connect API 키(.p8) 발급과 사용법

> App Store Connect API 키(.p8)는 한 번만 다운로드할 수 있어요. 역할, Issuer ID, Key ID, 폐기, Expo·fastlane·스크립트 사용법을 정리했어요.

원본 페이지: [App Store Connect API 키(.p8) 발급과 사용법](https://devoria.fr/ko/blog/app-store-connect-api-key-p8)
작성자: [Mehdi Azizi](https://devoria.fr/ko/mehdi-azizi)
게시일: 2026-11-04
최종 내용 수정: 2026-11-04


App Store Connect API 키가 있으면 EAS, fastlane, RevenueCat, 직접 만든 스크립트 같은 도구가 비밀번호나 이중 인증 없이 내 계정에서 작업할 수 있어요. **키의 공개 절반은 Apple이 보관하고, 비공개 절반인 `.p8` 파일은 내가 딱 한 번만 다운로드할 수 있어요.** 이 파일과 Issuer ID, Key ID로 토큰에 서명하는데, 대부분의 요청에서 토큰 유효 시간은 최대 20분이에요.

저는 TradaZen, Nolera를 포함한 iOS 앱을 Expo로 출시하고 있어요. App Manager 역할을 준 팀 키 하나를 RevenueCat, Expo 빌드, 그리고 스토어 페이지를 편집하는 커맨드라인 도구에 쓰고 있어요. 이 가이드는 2026년 11월 3일에 다시 확인한 Apple, Expo, fastlane 문서를 바탕으로 해요. 앱 코드에 넣는 서비스 키와 헷갈리지 마세요. 그건 [Expo 앱의 비밀 API 키](https://devoria.fr/ko/blog/expo-app-secret-api-key-security)에서 다뤄요.

## App Store Connect API 키가 하는 일

[Apple 문서](https://developer.apple.com/documentation/appstoreconnectapi/creating-api-keys-for-app-store-connect-api)에 따르면 App Store Connect API는 요청마다 JWT 토큰을 요구해요. 이 토큰은 내 비공개 키로 직접 생성하고 서명해요. 키는 이 API 전용이라 Apple의 다른 서비스에는 쓸 수 없어요.

장점은 한 문장으로 요약돼요. **로그인을 승인할 사람이 필요 없다는 거예요.** Apple ID로 로그인하면 이중 인증에 막혀서 자동화가 불가능해요. [EAS Submit iOS](https://devoria.fr/ko/blog/eas-submit-ios-publish-expo-app-store) 가이드에서 Expo 앱 제출이 어떻게 달라지는지 볼 수 있어요.

## 먼저 API 접근 요청하기

첫 키는 바로 만들 수 없어요. [App Store Connect 도움말](https://developer.apple.com/help/app-store-connect/get-started/app-store-connect-api)에 분명히 나와 있어요. **Account Holder가 먼저 API 접근을 요청해야 해요.** Users and Access를 열고 Integrations, 그다음 Request Access를 클릭해요. Apple은 요청을 건별로 검토해요.

Account Holder는 계정을 등록한 사람이에요. 처음 시작하는 분이라면 바로 본인이에요. 등록 과정은 [Apple 개발자 계정](https://devoria.fr/ko/blog/apple-developer-account-price-free-vs-99) 가이드에 자세히 있어요.

## 팀 키와 개인 키

Apple은 두 종류의 키를 제공해요. [문서](https://developer.apple.com/documentation/appstoreconnectapi/creating-api-keys-for-app-store-connect-api)와 [App Store Connect 도움말](https://developer.apple.com/help/app-store-connect/get-started/app-store-connect-api)에서 정리한 차이는 다음과 같아요.

| 기준                   | 팀 키                     | 개인 키            |
| ---------------------- | ------------------------- | ------------------ |
| 생성할 수 있는 사람    | Account Holder 또는 Admin | 거의 모든 사용자   |
| 접근 가능한 앱         | 예외 없이 전체            | 해당 사용자의 앱   |
| 권한                   | 선택한 역할               | 해당 사용자의 권한 |
| 키 개수                | 여러 개                   | 사람당 활성 키 1개 |
| 인증서와 프로필        | 가능, 역할에 따라         | 불가               |
| 판매, 재무, notaryTool | 역할에 따라               | 불가               |
| 토큰 필드              | `iss` = Issuer ID         | `sub` = `user`     |

Apple 기준으로 "거의 모든 사용자"란 Account Holder, Admin, App Manager, Customer Support, Developer, Marketing을 말해요. 단, Admin이나 Account Holder가 개인 키 생성 권한을 회수한 경우는 제외예요.

**Expo나 fastlane에는 팀 키를 고르세요.** 개인 키는 인증서와 프로필을 만드는 프로비저닝 엔드포인트에 접근할 수 없어요. [fastlane 문서](https://docs.fastlane.tools/app-store-connect-api/)도 프로비저닝 관련 접근에는 팀 키가 필요하다고 확인해 줘요.

## 키에 어떤 역할을 줄까

팀 키는 역할과 상관없이 계정의 모든 앱에 접근해요. 역할은 키가 무엇을 할 수 있는지를 정해요. **Apple은 Admin 키가 사용자를 만들고 삭제할 수 있다고 경고해요.** 용도를 커버하는 가장 작은 역할을 주세요. 아래 권한은 [Apple 역할 표](https://developer.apple.com/help/account/access/roles/)에서 가져왔어요.

| 키 용도                          | 가능한 역할                   |
| -------------------------------- | ----------------------------- |
| 빌드 업로드                      | Admin, App Manager, Developer |
| TestFlight 빌드 관리             | Admin, App Manager            |
| 인증서와 프로필 생성             | Admin, App Manager            |
| 앱 심사 제출                     | Admin, App Manager            |
| 상품과 가격 가져오기(RevenueCat) | 최소 App Manager              |
| 다른 팀 키 생성                  | Admin                         |

RevenueCat 행은 [RevenueCat 문서](https://www.revenuecat.com/docs/service-credentials/itunesconnect-app-specific-shared-secret/app-store-connect-api-key-configuration)에서 가져왔어요. Expo 가이드는 키에 [Admin 역할을 줘요](https://github.com/expo/fyi/blob/main/creating-asc-api-key.md). 제 앱에서는 App Manager로 충분해요. EAS가 이 역할로 배포 프로필을 만들고, RevenueCat도 상품을 가져와요.

키를 생성한 뒤에는 [이름도 역할도 바꿀 수 없어요](https://developer.apple.com/help/app-store-connect/get-started/app-store-connect-api). 바꾸려면 폐기하고 새로 생성해야 해요.

## 팀 키 만들기, 단계별로

Admin 또는 Account Holder 계정이 필요해요. [Apple](https://developer.apple.com/documentation/appstoreconnectapi/creating-api-keys-for-app-store-connect-api) 기준 절차예요.

1. **Users and Access를 열고** Integrations 탭으로 가요.
2. **왼쪽 열에서 App Store Connect API를 선택하고** Team Keys 탭을 눌러요.
3. **Generate API Key를 클릭하거나** + 버튼을 눌러요.
4. **키 이름을 정해요.** 나만 보는 이름이고 키의 일부가 아니에요. 사용할 도구 이름으로 지으세요.
5. **Access에서 역할을 고르고** Generate를 클릭해요.
6. **Download API Key 링크로 비공개 키를 다운로드해요.**

> 파일을 다운로드하는 순간 링크가 사라지고, Apple은 사본을 보관하지 않아요. 페이지를 닫기 전에 `.p8`을 안전한 곳에 저장하세요.

그다음 두 식별자를 적어 둬요. [Apple의 토큰 페이지](https://developer.apple.com/documentation/appstoreconnectapi/generating-tokens-for-api-requests)에 따르면 **Issuer ID는 Integrations 페이지 상단에** Copy 버튼과 함께 표시돼요. Key ID는 활성 키 목록에 있고, 마우스를 올리면 Copy Key ID가 나타나요. Issuer ID는 계정의 모든 팀 키에서 같아요. Key ID는 키마다 달라요.

개인 키는 더 간단해요. 내 사용자 프로필을 열고 Individual API Key까지 내려가서 Generate API Key를 클릭하면 돼요. 여기서도 다운로드는 한 번뿐이에요.

## .p8 파일 보관하기

Apple은 키를 비밀번호처럼 다루라고 해요. **공유하지 말고, 코드 저장소에 넣지 말고, 앱 코드에는 절대 포함하지 마세요.** 제 방식은 이래요.

- **프로젝트 밖의 폴더**, 또는 CI 도구의 시크릿 관리자.
- **키 폴더를 `.gitignore`에 추가**, 업로드하는 동안 파일이 프로젝트 안에 있어야 한다면요.
- **엄격한 권한.** App Store Connect용 커맨드라인 도구가 다른 계정이 읽을 수 있는 상태의 `.p8`을 거부했어요. `chmod 600`으로 해결했어요.
- **도구마다 키 하나.** Apple은 원하는 역할로 [여러 키를 생성](https://developer.apple.com/documentation/appstoreconnectapi/creating-api-keys-for-app-store-connect-api)할 수 있게 해 줘요.

마지막 항목은 처음엔 지키지 않았어요. 제 App Manager 키 하나를 RevenueCat, 빌드, 스토어 페이지 도구가 같이 써요. 폐기해야 하면 도구 세 개가 한꺼번에 멈춰요. **다시 한다면 도구마다 키를 따로 만들 거예요.** 다른 도구는 건드리지 않고 하나만 끊을 수 있도록요.

## Expo에서 사용하기

EAS에 키를 넘기는 방법은 세 가지예요.

- **EAS에 관리를 맡기기.** `eas credentials --platform ios`로 키를 만들고 Expo 서버에 보관할 수 있어요. 가장 간단한 방법이에요.
- **`eas.json`에 선언하기.** `submit` 프로필은 `ascApiKeyPath`, `ascApiKeyIssuerId`, `ascApiKeyId`를 받아요. [eas.json 레퍼런스](https://docs.expo.dev/eas/json/)에 따르면 이 필드에는 `$ASC_API_KEY_PATH` 같은 환경 변수를 쓸 수 있어요.
- **환경 변수로 넘기기.** [EAS CLI 저장소](https://github.com/expo/eas-cli/blob/main/packages/eas-cli/README.md)에 `EXPO_ASC_API_KEY_PATH`, `EXPO_ASC_KEY_ID`, `EXPO_ASC_ISSUER_ID`가 나와 있어요. 개인 키라면 Issuer ID는 빼요.

빌드할 때 알아 둘 한계가 있어요. [Expo 설명](https://docs.expo.dev/build-reference/ios-capabilities/)에 따르면 공식 API로는 App Group, Merchant ID, CloudKit 컨테이너를 연결할 수 없어요. 이 경우 로컬에서 Apple ID로 로그인해야 해요. 저도 Nolera 위젯의 앱 그룹에서 겪었어요. 키로 기능은 활성화됐지만 그룹은 연결되지 않았어요. 그래서 Apple 개발자 포털에서 직접 연결했어요. **기능 동기화가 막히면 `EXPO_NO_CAPABILITY_SYNC=1`로 끌 수 있어요.** 그리고 앱 ID에서 기능을 직접 활성화하면 돼요. 빌드 서명은 [iOS 인증서와 프로비저닝 프로필](https://devoria.fr/ko/blog/ios-certificate-provisioning-profile-expo)에서 자세히 다뤄요.

## fastlane에서 사용하기

[fastlane](https://docs.fastlane.tools/app-store-connect-api/)은 JSON 파일에서 키를 읽어요. `key_id`, `issuer_id`, 그리고 `.p8` 내용인 `key`는 필수예요. `duration`과 `in_house`는 선택이에요. 가짜 값으로 보면 이래요.

```json
{
  "key_id": "XXXXXXXXXX",
  "issuer_id": "your-issuer-id",
  "key": "-----BEGIN PRIVATE KEY-----\nMIGT...\n-----END PRIVATE KEY-----",
  "duration": 1200,
  "in_house": false
}
```

그다음 이 파일을 액션에 넘겨요. 예를 들어 `fastlane pilot distribute --api_key_path fastlane/cle.json`처럼요. Fastfile에서는 `app_store_connect_api_key` 액션이 `key_id`, `issuer_id`, `key_filepath`를 받아요. 세션 시간은 1,200초, 즉 20분을 넘을 수 없어요. 모든 액션이 지원하는 건 아니에요. 예를 들어 fastlane은 `produce`와 `pem`이 API 키로 동작하지 않는다고 안내해요.

## 직접 만든 스크립트에서 사용하기

도구 없이 쓰려면 토큰을 직접 만들어야 해요. [Apple이 정한 방식](https://developer.apple.com/documentation/appstoreconnectapi/generating-tokens-for-api-requests)은 이래요.

- **헤더**: `alg`는 `ES256`, `kid`는 내 Key ID, `typ`는 `JWT`.
- **페이로드, 팀 키**: `iss`는 Issuer ID, `iat`는 생성 시각, `exp`는 만료 시각, `aud`는 `appstoreconnect-v1`.
- **페이로드, 개인 키**: `iss` 대신 `sub`를 `user`로 넣어요.
- **유효 시간**: 20분을 넘으면 대부분의 요청에서 Apple이 토큰을 거부해요.

Python에서는 PyJWT 라이브러리와 암호화 의존성을 써요. [문서](https://pyjwt.readthedocs.io/en/stable/installation.html)대로 `pip install pyjwt[crypto]`로 설치해요. Mac 터미널에서는 따옴표를 붙여서 `pip install "pyjwt[crypto]"`로 입력하세요. 안 그러면 zsh가 대괄호를 거부해요.

```python
import time
import jwt

KEY_ID = "XXXXXXXXXX"
ISSUER_ID = "your-issuer-id"

with open("AuthKey_XXXXXXXXXX.p8") as f:
    private_key = f.read()

now = int(time.time())
token = jwt.encode(
    {"iss": ISSUER_ID, "iat": now, "exp": now + 20 * 60, "aud": "appstoreconnect-v1"},
    private_key,
    algorithm="ES256",
    headers={"kid": KEY_ID, "typ": "JWT"},
)
print(token)
```

그다음 Apple 예시처럼 `Authorization` 헤더에 넣어 보내요.

```bash
curl -H "Authorization: Bearer $TOKEN" "https://api.appstoreconnect.apple.com/v1/apps"
```

2026년 11월 3일에 제 컴퓨터에서 만든 일회용 키로 이 스크립트를 실행해 봤어요. 토큰의 헤더와 페이로드가 Apple 페이지와 일치했고 ES256 서명도 검증됐어요. 이 테스트 키는 Apple에 존재하지 않는 키라서 Apple API로 보내 보지는 않았어요. **토큰이 유효한 동안에는 같은 토큰을 재사용하세요.** 성능을 위해 Apple이 권장하는 방법이에요.

## 키 폐기하기

키를 잃어버렸거나, 유출됐거나, 더 이상 쓰는 도구가 없으면 바로 폐기하세요. [App Store Connect 도움말](https://developer.apple.com/help/app-store-connect/get-started/app-store-connect-api)에 따르면 Account Holder 또는 Admin 계정으로 다음을 해요.

1. Users and Access를 열고 Integrations로 가요.
2. Team Keys 또는 Individual Keys를 선택하고 Edit를 클릭해요.
3. 폐기할 키를 체크하고 Revoke Key를 눌러요.
4. Revoke로 확인해요.

**폐기한 키는 다시 활성화할 수 없어요.** [Apple은 이 키를](https://developer.apple.com/documentation/appstoreconnectapi/revoking-api-keys) 30일 동안 Revoked 아래에 표시해요. 그 키를 쓰던 도구는 모두 인증에 실패해요. Expo에서는 "[App Store Connect rejected the API authentication credentials](https://github.com/expo/eas-cli/blob/main/packages/build-tools/src/steps/utils/ios/AscApiClient.ts)"라는 메시지가 떠요. 이 메시지와 다른 업로드 실패는 [EAS 업로드 오류와 해결 방법](https://devoria.fr/ko/blog/eas-submit-ios-errors-fix)에서 설명해요. 키가 유출된 게 아니라면 새 키를 먼저 준비한 다음 기존 키를 끊으세요. 유출됐다면 Apple은 즉시 폐기하라고 해요.

내 개인 키는 프로필, Individual API Key, Revoke 순서로 폐기해요.

## 제 .p8 키 체크리스트

- Account Holder가 API 접근을 요청했어요.
- 빌드나 프로필에 쓰는 키라면 팀 키예요.
- 역할은 용도를 커버하는 가장 작은 것이고, 이름에 사용하는 도구가 드러나요.
- `.p8`은 저장소 밖에, 엄격한 권한과 암호화된 백업과 함께 보관돼 있어요.
- Issuer ID와 Key ID는 파일 없이 따로 적어 뒀어요.
- 도구마다 키가 있어서 하나만 폐기할 수 있어요.

## 키를 노출하지 않고 출시 자동화하기

키는 전체 과정의 한 조각일 뿐이에요. [iOS & Android Kit](https://devoria.fr/ko/kits/ios)는 구독까지 포함된 제 앱의 시작 코드에서 출발해, 내 속도에 맞춰 네 단계로 App Store까지 안내해요. 이 키로 RevenueCat을 연결한다면 전체 구성은 [RevenueCat과 iOS 인앱 구독](https://devoria.fr/ko/blog/revenuecat-ios-in-app-subscription-setup)에 있어요.

첫 출시를 준비 중이라면 [무료 진단을 받아 보세요](https://devoria.fr/ko/diagnostic). 무엇이 진짜 막고 있는지 알려 주고, Apple 리젝 방지 체크리스트도 보내 드려요. [App Store에 앱 출시하기](https://devoria.fr/ko/expertise/publish-app-on-app-store) 페이지는 스토어 페이지부터 승인까지 모든 단계를 다뤄요.

## 자주 묻는 질문

### App Store Connect API 키는 어떻게 만드나요?

먼저 Account Holder가 API 접근을 요청해요. 그다음 Admin이 Users and Access, Integrations 탭, App Store Connect API, Team Keys로 가요. Generate API Key를 클릭하고 이름과 역할을 정해 키를 생성한 뒤 `.p8` 파일을 다운로드해요.

### 잃어버린 .p8 키를 다시 다운로드할 수 있나요?

아니요. 파일은 한 번만 다운로드할 수 있고 Apple은 사본을 보관하지 않아요. 잃어버린 키를 폐기하고 새 키를 생성한 뒤, 그 키를 쓰던 도구를 모두 업데이트하세요.

### Issuer ID와 Key ID는 어디서 찾나요?

App Store Connect의 Users and Access 메뉴, Integrations 탭에 있어요. Issuer ID는 페이지 상단에 표시돼요. Key ID는 활성 키 목록에 있어요. 개인 키는 Issuer ID를 쓰지 않아요.

### Expo에서 쓰는 키에는 어떤 역할을 줘야 하나요?

Expo 가이드는 Admin 역할을 줘요. Apple 역할 표에 따르면 빌드 업로드와 인증서, 프로필 생성에는 App Manager로 충분해요. 제 Expo 빌드에 쓰는 키도 이 역할이에요.

### API 키의 역할을 바꿀 수 있나요?

아니요. Apple은 생성 후 키의 이름도 역할도 바꿀 수 없게 해요. 폐기하고 올바른 역할로 새 키를 생성하세요.

### App Store Connect API 키는 만료되나요?

Apple 문서에는 키 만료에 대한 언급이 없고 폐기만 나와 있어요. 만료되는 건 키로 서명한 토큰이고, 대부분의 요청에서 최대 20분이에요.


## 내 프로젝트

[Review Kit](https://devoria.fr/ko/kits/app-review): 제 App Store 심사 체크리스트, 수정해서 통과한 Apple 리젝 사례, Google Play 체크리스트, Claude Code 스킬 3개를 담았어요. ₩73,000.

[iOS & Android Kit](https://devoria.fr/ko/kits/ios): Claude Code로 iPhone·Android 앱을 만들어 보세요. 제 앱들의 시작 코드, 스토어 출시까지의 과정, 모든 키트를 담았어요. ₩148,000.

[진단: 내 아이폰 앱까지 남은 거리](https://devoria.fr/ko/diagnostic): 7개 질문, 60초. 아이폰 앱 출시를 진짜 가로막는 게 뭔지, 4단계 로드맵, 나에게 맞는 키트까지 알려드려요.
