---
title: "설치 링크와 딥링크 | Tajo"
description: "앱 배포용 설치 URL을 생성하고, 사용자를 앱의 특정 화면으로 이동시키는 딥링크를 만듭니다"
url: https://tajo.io/kr/docs/stripe-apps/install-links/
markdown: https://tajo.io/kr/docs/stripe-apps/install-links.md
lang: ko-KR
author: "Set Noa"
author_url: https://tajo.io/kr/set-noa/
robots: noindex
---

Tajo 사전 이용 신청

이름과 회사 이메일 주소를 입력하세요. Tajo 이용 신청을 확인할 수 있는 링크를 이메일로 보내드립니다.

# 설치 링크와 딥링크

[Set Noa](https://tajo.io/kr/set-noa/)

설치 링크를 사용하면 마켓플레이스 밖에서도 Stripe App을 배포할 수 있고, 딥링크를 사용하면 설치된 앱의 특정 화면으로 사용자를 바로 이동시킬 수 있습니다. 두 가지 모두 매끄러운 온보딩과 연동 흐름에 꼭 필요합니다.

Caution

**상태: 예정, 아직 구축되지 않음.** Tajo에는 Stripe App이 없으므로 이 섹션의 어떤 것도 현재 설치할 수 없습니다. 이 페이지에 나오는 앱 식별자, URL, 자격 증명은 실제로 동작하는 엔드포인트가 아니라 예시용 자리표시자입니다.

## 설치 링크

설치 링크는 판매자가 앱을 설치할 때 사용하는 직접 URL을 제공합니다. 사용자가 설치 링크를 클릭하면 Stripe가 설치 과정을 처리한 뒤 지정한 URI로 다시 리디렉션합니다.

### 사전 준비

설치 링크를 사용하기 전에 앱 매니페스트에서 `allowed_redirect_uris`를 설정하십시오.

```json
{
  "id": "com.tajo.brevo-integration",
  "allowed_redirect_uris": [
    "https://tajo.io/stripe/callback",
    "https://tajo.io/stripe/oauth/complete"
  ]
}
```

### 설치 링크 형식

```
https://marketplace.stripe.com/oauth/v2/authorize?client_id=APP_ID&redirect_uri=REDIRECT_URI&state=STATE_VALUE
```

| 파라미터 | 필수 여부 | 설명 |
| --- | --- | --- |
| `client_id` | 필수 | 앱 ID (예: `com.tajo.brevo-integration`) |
| `redirect_uri` | 필수 | `allowed_redirect_uris` 중 하나와 일치해야 합니다 |
| `state` | 권장 | CSRF 방어를 위한 무작위 문자열 |

### 리디렉션 파라미터

설치가 성공하면 Stripe는 다음 쿼리 파라미터와 함께 사용자를 `redirect_uri`로 리디렉션합니다.

| 파라미터 | 설명 |
| --- | --- |
| `user_id` | 앱을 설치한 계정의 Stripe 사용자 ID |
| `account_id` | Stripe 계정 ID (예: `acct_xxxxx`) |
| `state` | 요청 시 전달한 `state` 값 (CSRF 검증용) |
| `install_signature` | 설치가 정상적인지 확인하는 HMAC 서명 |

리디렉션 URL 예시입니다.

```
https://tajo.io/stripe/callback
  ?user_id=usr_xxxxx
  &account_id=acct_xxxxx
  &state=abc123random
  &install_signature=sig_xxxxx
```

### CSRF 방어

사이트 간 요청 위조 공격을 막으려면 항상 `state` 파라미터를 사용하십시오.

```javascript
import crypto from 'crypto';

// Generate a random state value and store it in the session
const generateInstallLink = (req, res) => {
  const state = crypto.randomBytes(32).toString('hex');

  // Store state in session for later verification
  req.session.stripeInstallState = state;

  const installUrl = new URL('https://marketplace.stripe.com/oauth/v2/authorize');
  installUrl.searchParams.set('client_id', 'com.tajo.brevo-integration');
  installUrl.searchParams.set('redirect_uri', 'https://tajo.io/stripe/callback');
  installUrl.searchParams.set('state', state);

  res.redirect(installUrl.toString());
};

// Handle the redirect callback
const handleInstallCallback = async (req, res) => {
  const { state, user_id, account_id, install_signature } = req.query;

  // Verify state matches what we stored
  if (state !== req.session.stripeInstallState) {
    return res.status(403).json({ error: 'Invalid state parameter' });
  }

  // Clear the stored state
  delete req.session.stripeInstallState;

  // Verify the install signature
  if (!verifyInstallSignature(install_signature, account_id)) {
    return res.status(403).json({ error: 'Invalid install signature' });
  }

  // Process the successful installation
  await processInstallation(user_id, account_id);

  res.redirect('/dashboard/stripe-connected');
};
```

### 서명 검증

앱의 서명 시크릿으로 `install_signature`를 검증하십시오.

```javascript
import crypto from 'crypto';

const verifyInstallSignature = (signature, accountId) => {
  const signingSecret = process.env.STRIPE_APP_SIGNING_SECRET;

  const expectedSignature = crypto
    .createHmac('sha256', signingSecret)
    .update(accountId)
    .digest('hex');

  return crypto.timingSafeEqual(
    Buffer.from(signature),
    Buffer.from(expectedSignature)
  );
};
```

Caution

타이밍 공격을 막으려면 서명 비교에 항상 `crypto.timingSafeEqual`을 사용하십시오. 단순 문자열 비교(`===`)는 절대 사용하지 마십시오.

### 서명 시크릿

앱의 서명 시크릿은 Stripe 대시보드의 앱 설정에서 확인할 수 있습니다. 다음 용도로 사용하십시오.

- 리디렉션 콜백의 설치 서명 검증
- Stripe에서 오는 웹훅 페이로드 검증
- 백엔드와 Stripe 사이의 요청 인증

서명 시크릿은 안전하게 보관하십시오.

```bash
# Set as environment variable
export STRIPE_APP_SIGNING_SECRET="whsec_xxxxx"
```

서명 시크릿을 소스 코드에 하드코딩하거나 버전 관리에 커밋해서는 안 됩니다.

## 딥링크

딥링크는 설치된 Stripe App의 특정 화면으로 사용자를 바로 이동시킵니다. 이메일, 알림, 지원 페이지 같은 외부 커뮤니케이션에서 사용자를 관련 앱 화면으로 안내할 때 사용하십시오.

### 딥링크 URL 형식

```
https://dashboard.stripe.com/MODE/acct_ID/PAGE?apps[APP_ID][TARGET]=VIEWPORT_ID
```

| 구성 요소 | 설명 | 예시 |
| --- | --- | --- |
| `MODE` | `live` 또는 `test` | `live` |
| `acct_ID` | 대상 Stripe 계정 ID | `acct_1234567890` |
| `PAGE` | 대시보드 페이지 경로 | `customers/cus_xxxxx` |
| `APP_ID` | 앱의 ID | `com.tajo.brevo-integration` |
| `TARGET` | `drawer` 또는 `modal` | `drawer` |
| `VIEWPORT_ID` | 열려는 뷰포트 | `stripe.dashboard.customer.detail` |

### drawer와 modal 타깃 비교

| 타깃 | 동작 | 사용 사례 |
| --- | --- | --- |
| `drawer` | 측면 패널(드로어)에서 앱을 엽니다 | 기본 앱 사용 방식, 페이지와 나란히 보는 맥락 |
| `modal` | 전체 화면 모달 오버레이로 앱을 엽니다 | 집중이 필요한 워크플로, 온보딩, 복잡한 양식 |

### 딥링크 예시

#### 드로어에서 고객 상세 화면 열기

```
https://dashboard.stripe.com/live/acct_xxxxx/customers/cus_xxxxx
  ?apps[com.tajo.brevo-integration][drawer]=stripe.dashboard.customer.detail
```

#### 모달에서 설정 열기

```
https://dashboard.stripe.com/live/acct_xxxxx/settings
  ?apps[com.tajo.brevo-integration][modal]=stripe.dashboard.settings
```

#### 온보딩 흐름 열기

```
https://dashboard.stripe.com/live/acct_xxxxx/dashboard
  ?apps[com.tajo.brevo-integration][modal]=stripe.dashboard.onboarding
```

#### 테스트 모드에서 결제 상세 화면 열기

```
https://dashboard.stripe.com/test/acct_xxxxx/payments/pi_xxxxx
  ?apps[com.tajo.brevo-integration][drawer]=stripe.dashboard.payment.detail
```

### 딥링크를 프로그래밍 방식으로 생성하기

```javascript
const generateDeepLink = ({
  accountId,
  mode = 'live',
  page,
  appId = 'com.tajo.brevo-integration',
  target = 'drawer',
  viewport,
}) => {
  const baseUrl = `https://dashboard.stripe.com/${mode}/${accountId}/${page}`;
  const params = new URLSearchParams();
  params.set(`apps[${appId}][${target}]`, viewport);

  return `${baseUrl}?${params.toString()}`;
};

// Generate a link to view a customer's Brevo profile
const customerLink = generateDeepLink({
  accountId: 'acct_xxxxx',
  page: 'customers/cus_xxxxx',
  viewport: 'stripe.dashboard.customer.detail',
});

// Generate a link to app settings
const settingsLink = generateDeepLink({
  accountId: 'acct_xxxxx',
  page: 'settings',
  viewport: 'stripe.dashboard.settings',
  target: 'modal',
});
```

### 커뮤니케이션에서 딥링크 활용하기

딥링크는 특히 다음 상황에서 유용합니다.

- **이메일 알림**: “이 고객의 Brevo 동기화 상태 보기”
- **지원 답변**: “여기를 클릭하여 연동 설정을 확인하세요”
- **온보딩 이메일**: “Brevo 설정을 완료하세요”
- **오류 알림**: “고객 X의 동기화 문제를 확인하세요”

```html
<!-- Example in an email template -->
<a href="https://dashboard.stripe.com/live/acct_xxxxx/customers/cus_xxxxx?apps[com.tajo.brevo-integration][drawer]=stripe.dashboard.customer.detail">
  View Brevo Profile in Stripe
</a>
```

## 설치 링크와 딥링크 결합하기

최상의 온보딩 경험을 위해 설치 링크와 설치 후 딥링크를 결합하십시오.

1. 사용자가 웹사이트나 이메일에서 **설치 링크**를 클릭합니다
2. 사용자가 앱을 설치하고 콜백 URL로 리디렉션됩니다
3. 콜백에서 설치를 처리한 뒤, 온보딩 뷰포트를 여는 **딥링크**로 사용자를 리디렉션합니다

```javascript
const handleInstallCallback = async (req, res) => {
  const { account_id, install_signature, state } = req.query;

  // Verify state and signature
  // ... (verification code)

  // Process installation
  await processInstallation(account_id);

  // Redirect to the app's onboarding view via deep link
  const onboardingLink = generateDeepLink({
    accountId: account_id,
    page: 'dashboard',
    viewport: 'stripe.dashboard.onboarding',
    target: 'modal',
  });

  res.redirect(onboardingLink);
};
```

Tip

설치 링크와 딥링크는 모든 환경에서 정상 동작하도록 라이브 모드와 테스트 모드에서 항상 테스트하십시오.
