<!-- canonical: https://docs.axelabs.ai/partner/registration -->
<!-- source: content/partner/registration.mdx -->

---
title: Microsoft Entra ID 앱 등록
description: Blueprint · Vaultwarden · Frame MCP · Blueprint MCP 4개 app 등록 — CLI 1줄 (5분) 또는 portal (~50분).
---

# Microsoft Entra ID 앱 등록

귀사 Microsoft Entra ID tenant 에 **4 개의 app** 을 등록합니다.

> 🚀 **권장: Option A — CLI 1 줄 (~5분)**
> `https://docs.axelabs.ai/axelabs-bootstrap.sh` 다운로드 → `az login` → 1 줄 실행 → JSON pack 회신. 본 페이지의 [Option A](#option-a--cli-1-줄-권장) 섹션 자체에 모든 절차가 들어있습니다 (별도 메시지/파일 의존 없음).
>
> Option B (portal 수작업, ~40분) 은 `az` CLI 가 환경상 안 될 때 fallback 입니다.

---

## Option A — CLI 1 줄 (권장)

### 1. 사전 확인 (5분)

| 항목 | 확인 방법 |
|---|---|
| `az` CLI 설치 (≥ 2.50) | `az --version`; 없으면 `brew install azure-cli` (macOS) / [공식 설치 가이드](https://learn.microsoft.com/cli/azure/install-azure-cli) |
| `jq` 설치 | `jq --version`; 없으면 `brew install jq` |
| **Admin consent grant 권한** (다음 중 하나) | `az ad signed-in-user show` 후 본인 역할 확인. ★ admin consent 가 자동으로 잡혀야 직원/agent 가 claude.ai Custom Connector 등록 시 consent prompt 안 나옴 |
| ・ Global Administrator (권장 — 모든 권한) | Entra ID → Roles and administrators → "Global Administrator" |
| ・ Privileged Role Administrator | 같은 곳에서 확인 |
| ・ Cloud Application Administrator | 같은 곳에서 확인 |
| ・ Application Administrator | 같은 곳에서 확인 |
| `{customer}.axelabs.ai` 가 Entra tenant 의 verified domain 인지 | 운영자 측이 사전 등록함 — 미등록 시 §[도메인 검증 흐름](#도메인-검증-흐름) 참조 |

### 2. 스크립트 다운로드 + 무결성 검증

```bash
# 다운로드
curl -fsSL https://docs.axelabs.ai/axelabs-bootstrap.sh -o axelabs-bootstrap.sh
chmod +x axelabs-bootstrap.sh

# SHA-256 검증 (값이 일치해야 신뢰)
shasum -a 256 axelabs-bootstrap.sh
# 예상: ae6f771e85f7ec49d75bc082e1e0d42b106ba095e03d9adad430e590c2c4aefb  axelabs-bootstrap.sh
```

> ⚠️ 체크섬이 다르면 즉시 운영자 (`ai@axellc.com`) 에게 연락. 위 값은 본 docs 페이지 (https://docs.axelabs.ai/partner/registration) 와 함께 갱신됩니다.

### 3. Azure 로그인

```bash
# 귀사 tenant 로 로그인 (브라우저 팝업)
az login --allow-no-subscriptions --tenant <YOUR_TENANT_ID_OR_DOMAIN>

# 예 (도메인)
az login --allow-no-subscriptions --tenant realchoice.onmicrosoft.com

# 또는 tenant ID (GUID)
az login --allow-no-subscriptions --tenant 381cc823-2bb2-43a7-9a27-68ea3afacdff
```

> ⚠️ **`--allow-no-subscriptions` 가 필수**. Microsoft 365 만 사용하고 Azure subscription (구독 결제) 이 없는 tenant 에서 일반 `az login` 은 "No subscriptions found for ..." 에러로 종료됩니다. bootstrap.sh 는 Microsoft Graph (app registration) 만 호출하므로 subscription 불필요 — 본 flag 로 우회.

**검증** (subscription 없이도 ok):

```bash
az account show
# 기대 출력: subscription 필드 없이도 tenantId / homeTenantId / user.name 표시되면 OK
# (subscription 보유 tenant 라면 isDefault: true 인 subscription 1개 표시도 정상)
```

`az account show` 가 `Please run 'az login' to setup account.` 를 반환하면 step 3 재시도. 정상 출력이면 step 4 진행.

### 4. 부트스트랩 실행 — 1 줄

```bash
./axelabs-bootstrap.sh <customer_id> <public_domain>

# 예 (realchoice)
./axelabs-bootstrap.sh realchoice realchoice.axelabs.ai
```

`<customer_id>` 는 운영자가 사전 제공 (예: `realchoice`). `<public_domain>` 도 운영자 제공 (`{customer}.axelabs.ai`).

스크립트가 자동 처리:
1. `az` 와 `jq` 가용성 확인
2. 4 개 app 등록 (이미 존재하면 reuse — idempotent, destructive 작업 없음)
3. 각 app 의 client_secret 발급 (`--append` 로 기존 secret 보존, overlap window)
4. Frame MCP + Blueprint MCP 의 Application ID URI + `mcp.access` scope + manifest 설정
5. Delegated permission + admin consent (실행자 = Global Admin 이어야 자동)
6. Tenant ID 자동 캡처
7. 결과를 `axelabs-bootstrap-<customer_id>.json` 으로 출력 (mode 600)

### 5. 출력 파일 회신

스크립트 실행 후 생성된 파일:

```
axelabs-bootstrap-<customer_id>.json   # 예: axelabs-bootstrap-realchoice.json
```

JSON 스키마 (`axelabs-bootstrap/v1`):

```json
{
  "schema": "axelabs-bootstrap/v1",
  "customer": "realchoice",
  "public_domain": "realchoice.axelabs.ai",
  "tenant_id": "<GUID>",
  "generated_by": "<your-az-login-email>",
  "apps": {
    "blueprint":   { "client_id": "...", "client_secret": "..." },
    "vaultwarden": { "client_id": "...", "client_secret": "..." },
    "frame_mcp":   {
      "client_id": "...",
      "client_secret": "...",
      "application_id_uri": "https://realchoice.axelabs.ai/frame/mcp",
      "scope": "mcp.access",
      "redirect_uris": ["https://claude.ai/api/mcp/auth_callback", "https://claude.com/api/mcp/auth_callback"]
    },
    "blueprint_mcp": {
      "client_id": "...",
      "client_secret": "...",
      "application_id_uri": "https://realchoice.axelabs.ai/blueprint/mcp",
      "scope": "mcp.access",
      "redirect_uris": ["https://claude.ai/api/mcp/auth_callback", "https://claude.com/api/mcp/auth_callback"]
    }
  }
}
```

운영자에게 [안전 채널로 전달](/partner/handoff) (1Password Send / Bitwarden Send view-once). 평문 메일·채팅 금지.

### 6. 운영자 처리 확인

운영자가 `axe customer ingest realchoice axelabs-bootstrap-realchoice.json` 으로 흡수 → vault 에 secret push + customers.yaml 자동 갱신 → 다음 단계 [배포 협의](/partner/deploy) 진행.

### 도메인 검증 흐름

`{customer}.axelabs.ai` 는 `axelabs.ai` zone (운영 주체 = 액스코퍼레이션 주식회사 관리) 의 서브도메인. 따라서 **TXT 검증은 운영자가 axelabs.ai zone 에 추가**합니다 — 귀사 IT 에서는 다음 두 경로 중 하나:

- 운영자가 사전 등록한 경우: 스크립트가 `--skip-domain-verify` 기본값으로 가정. 그대로 실행.
- 사전 등록 안 된 경우: `./axelabs-bootstrap.sh ... --request-domain-verify` 실행 → stdout 에 TXT 값 표시 → 운영자에게 한 줄 전달 → 운영자가 Cloudflare API 로 추가 후 → 스크립트 재실행.

자세한 도메인 모델은 [DNS 준비](/partner/domain-prep) 참조.

### 함정 (Option A)

| 함정 | 결과 | 회피 |
|---|---|---|
| `az login` 안 함 | "Please run 'az login'" | step 3 |
| **Azure subscription 없는 tenant 에서 `az login` 만 실행** | "No subscriptions found for ...". tenant level access 만 필요한 작업인데도 종료 | **`az login --allow-no-subscriptions --tenant <id>`** 로 실행. M365 만 쓰는 tenant 의 표준 함정 (2026-05-25 트루비아 측 첫 발견) |
| 실행자가 Global Admin / Application Administrator / Cloud App Admin / Privileged Role Admin 모두 아님 | admin consent grant 실패 (warning) → claude.ai Custom Connector 등록 시 일반 직원이 consent prompt 직면 (개인 grant 못 함 → 차단) | (a) 회사 IT 의 위 role 보유자가 재실행, (b) 또는 portal UI 에서 admin consent grant: **Entra ID → App registrations → `Frame MCP` (또는 `Blueprint MCP`) → API permissions → "Grant admin consent for `{tenant}`"** 클릭, (c) 또는 admin consent URL 직접 방문: `https://login.microsoftonline.com/{tenant_id}/adminconsent?client_id={client_id}` |
| `<public_domain>` 검증 안 됨 | Frame MCP Application ID URI 등록 실패 | §[도메인 검증 흐름](#도메인-검증-흐름) |
| 같은 customer_id 로 재실행 | secret 만 추가 발급 (기존 보존) — 정상 동작 | — |
| Apple Silicon 의 `jq` 누락 | "jq: command not found" | `brew install jq` |

---

## Option B — Portal 수작업 (fallback, ~40분)

`az` CLI 사용 불가한 환경 (admin 정책상 차단 등) 일 때만.

귀사 Microsoft Entra ID tenant 에 **4 개의 app** 을 등록합니다. 각각 다른 용도:

| # | App 이름 | 용도 | Platform | Secret |
|---|---|---|---|---|
| 1 | `Blueprint` | Web UI 로그인 | Web | 발급 |
| 2 | `Vaultwarden` | 회사 password vault SSO | Web | 발급 |
| 3 | `Frame MCP` | 회계 시스템 OAuth (claude.ai connector) | Web | 발급 |
| 4 | `Blueprint MCP` | Blueprint MCP OAuth (claude.ai connector) | Web | 발급 |

## 사전 준비

- Azure portal 접속 권한 (Global Admin 또는 Application Administrator)
- 회사 도메인 검증 완료 ([DNS 준비](/partner/domain-prep) 우선 진행)
- 서비스 노출 domain 확인 (AXE 측이 제공, 예: `realchoice.axelabs.ai`)

---

## App #1 — Blueprint (Web UI 로그인)

### 등록

1. Azure portal → **Microsoft Entra ID** → **App registrations** → **+ New registration**
2. **Name**: `Blueprint`
3. **Supported account types**: `Accounts in this organizational directory only (Single tenant)`
4. **Redirect URI**:
   - Platform: **Web**
   - URI: `https://{customer}.axelabs.ai/api/auth/callback/azure-ad`
   - 예: `https://realchoice.axelabs.ai/api/auth/callback/azure-ad`
5. **Register**

### Client Secret 발급

1. 좌측 **Certificates & secrets** → **+ New client secret**
2. Description: `blueprint-{customer}-2026-06`
3. Expires: **180 days** (또는 회사 정책)
4. **Add** → **VALUE** 컬럼 즉시 복사 (이후 안 보임)

### API Permissions

좌측 **API permissions** → **+ Add a permission** → **Microsoft Graph** → **Delegated**:

- `User.Read`
- `Mail.Read`
- `Mail.Send`
- `Chat.ReadWrite`
- `ChatMessage.Send`

**Add permissions** → 권한 있으시면 **Grant admin consent for `{tenant}`**.

### 수집할 값

```
Blueprint_CLIENT_ID    : <Overview 페이지의 Application (client) ID>
Blueprint_CLIENT_SECRET: <위에서 복사한 VALUE>
```

---

## App #2 — Vaultwarden (password vault SSO)

### 등록

1. **+ New registration**
2. **Name**: `Vaultwarden`
3. **Supported account types**: `Single tenant`
4. **Redirect URI**:
   - Platform: **Web**
   - URI: `https://{customer}.axelabs.ai/vault/identity/connect/oidc-signin`
5. **Register**

### Client Secret

App #1 과 동일 절차로 secret 발급, VALUE 캡처.

### API Permissions

**Microsoft Graph → Delegated**:

- `openid`
- `profile`
- `offline_access`
- `User.Read`

**Grant admin consent**.

### 수집할 값

```
Vaultwarden_CLIENT_ID    : <...>
Vaultwarden_CLIENT_SECRET: <...>
```

---

## App #3 — Frame MCP (회계 시스템) ⚠️ 가장 복잡

이 app 만 **App ID URI + custom scope** 가 추가로 필요합니다. 4 단계.

### 3-1. 등록

1. **+ New registration**
2. **Name**: `Frame MCP`
3. **Supported account types**: `Single tenant`
4. **Redirect URI**: 일단 비워두고 **Register**

### 3-2. Authentication (Web platform)

좌측 **Authentication** → **+ Add a platform** → **Web**:

- Redirect URIs (둘 다 추가):
  - `https://claude.ai/api/mcp/auth_callback`
  - `https://claude.com/api/mcp/auth_callback`

같은 페이지 하단 **Advanced settings**:
- **Allow public client flows**: **Yes** (PKCE 가능)

**Save**.

### 3-3. Expose an API

⚠️ **사전 조건**: [DNS / 도메인 준비](/partner/domain-prep) 가 완료되어 `{customer}.axelabs.ai` 가 검증된 사용자 도메인이어야 합니다.

좌측 **Expose an API**:

1. **Application ID URI** → **Add** (또는 Edit) → 입력:
   ```
   https://{customer}.axelabs.ai/frame/mcp
   ```
   예: `https://realchoice.axelabs.ai/frame/mcp`
2. **Save**

3. **Add a scope**:
   - Scope name: `mcp.access`
   - Who can consent: `Admins and users`
   - Admin consent display name: `Access Frame MCP as the signed-in user`
   - Admin consent description: `Allow the application to access Frame MCP on behalf of the signed-in user.`
   - User consent display name: `Access Frame MCP`
   - User consent description: `Allow this app to access Frame MCP for you.`
   - State: **Enabled**
4. **Add scope**

전체 scope URI: `https://{customer}.axelabs.ai/frame/mcp/mcp.access`

### 3-4. API Permissions (자기 자신 참조)

좌측 **API permissions** → **+ Add a permission** → **My APIs** 탭 → **Frame MCP** → **Delegated** → `mcp.access` 체크 → **Add permissions**.

상단 **Grant admin consent for `{tenant}`** 클릭.

### 3-5. Token Configuration

좌측 **Token configuration** → **+ Add optional claim** → **ID** → `email`, `upn` 체크 → **Add**.

(id_token 이 verified email 없는 사용자도 처리할 수 있도록.)

### 3-6. Manifest (선택 확인)

좌측 **Manifest** → JSON 안에서 `"requestedAccessTokenVersion"` 값 확인:
- **`null`** (기본) → v1 토큰 (aud = Application ID URI) — Anthropic Claude 호환에 권장
- `2` → v2 토큰 (aud = client_id GUID)

기본값 `null` 그대로 두기를 권장 (claude.ai 의 audience 검증 호환).

### 3-7. Client Secret 발급

좌측 **Certificates & secrets** → **+ New client secret**:
- Description: `frame-mcp-{customer}-2026-06`
- Expires: **24 months**
- **Add** → VALUE 즉시 복사

### 수집할 값

```
Frame_MCP_CLIENT_ID    : <Overview 페이지의 Application (client) ID>
Frame_MCP_CLIENT_SECRET: <위에서 복사한 VALUE>
```

---

## App #4 — Blueprint MCP (Blueprint MCP OAuth)

**App #3 Frame MCP 와 동일 절차** — 호스트 경로만 `/frame/mcp` → `/blueprint/mcp` 로 교체:

| Step | Frame MCP 값 | Blueprint MCP 값 |
|---|---|---|
| Name | `Frame MCP` | `Blueprint MCP` |
| Application ID URI (3-3) | `https://{customer}.axelabs.ai/frame/mcp` | `https://{customer}.axelabs.ai/blueprint/mcp` |
| Scope URI | `https://{customer}.axelabs.ai/frame/mcp/mcp.access` | `https://{customer}.axelabs.ai/blueprint/mcp/mcp.access` |
| Client secret description | `frame-mcp-{customer}-2026-06` | `blueprint-mcp-{customer}-2026-06` |

나머지 (Authentication Web platform / Redirect URIs / Add public client flows Yes / Expose an API mcp.access scope / API Permissions self-reference + admin consent / Token Configuration optional claims / Manifest accessTokenAcceptedVersion=null) **모두 App #3 과 동일**.

### 수집할 값

```
Blueprint_MCP_CLIENT_ID    : <Overview 페이지의 Application (client) ID>
Blueprint_MCP_CLIENT_SECRET: <위에서 복사한 VALUE>
```

---

## 4. Tenant ID 수집 (1 회)

4개 app 공통. 아무 app 의 Overview 페이지에서 **Directory (tenant) ID** 복사.

또는 Azure portal → Microsoft Entra ID → Overview → Tenant ID.

```
TENANT_ID: &lt;GUID&gt;
```

---

## 5. 회신 형식

[운영자에게 넘길 값](/partner/handoff) 페이지의 회신 템플릿에 채워서 보내주세요.

## 함정 모음

| 함정 | 결과 | 회피 |
|---|---|---|
| Application ID URI 에 검증 안 된 도메인 사용 | 등록 거부 | [DNS 준비](/partner/domain-prep) 먼저 |
| Web platform 누락 (Mobile/desktop 만) | redirect_uri 등록 실패 | Web platform 명시 |
| Allow public client flows = No + secret 없음 | OAuth 실패 (AADSTS7000218) | Yes 또는 secret 발급 |
| `mcp.access` scope 안 만들고 API permissions 만 추가 | scope 호출 시 실패 | Expose an API 단계 먼저 |
| Application ID URI 와 scope URI 불일치 | AADSTS9010010 | 둘 다 같은 URL prefix |
| Manifest 의 accessTokenAcceptedVersion=2 (Anthropic 비호환) | mcp_client_invalid | null 또는 1 |
| **Admin consent 미 grant** (App #1 Blueprint / App #3 Frame MCP / 향후 Blueprint MCP) | 일반 직원이 첫 로그인 또는 claude.ai Custom Connector 등록 시 AADSTS65001 (`invalid_grant`) 차단. 본인 단독 grant 불가 | App 별 **API permissions → Grant admin consent for `{tenant}`** 버튼 클릭. 본인이 권한 부족 시 회사 IT 의 Global Admin / App Admin / Cloud App Admin / Privileged Role Admin 중 1인에게 의뢰. CLI 대안: `az ad app permission admin-consent --id <client_id>` (같은 role 필요) |

다음: [DNS / 도메인 준비](/partner/domain-prep) →
