# 이미지 URL에 서명하기

OG 이미지 URL은 다음과 같습니다.

```
https://api.mocco.club/v1/og/<project id>/article.png?brand=Acme%20Docs&title=Install%20in%20five%20minutes&s=<signature>
```

항목은 쿼리 파라미터이고 `s`가 서명입니다. URL 전체를 페이지의 `og:image`(와 `twitter:image`) 태그에 넣으세요. 이미지를 불러올 때 API 키는 필요 없습니다. 서명이 곧 인증입니다.

먼저 프로젝트의 서명 시크릿을 만드세요([서명 시크릿](https://www.mocco.club/docs/ko/articles/27m78b-overview#서명-시크릿) 참고).

## 콘솔에서

프로젝트를 열고 **API 키**로 가서 **OG 이미지 서명** 카드의 **템플릿 갤러리 열기**를 누릅니다. **OG 이미지** 페이지는 모든 멤버가 쓸 수 있습니다.

1. 템플릿을 고릅니다. 항목 입력란이 나타나고, **브랜드**에는 프로젝트 이름이, **강조 색상**에는 헬프 센터에 강조 색상이 있으면 그 색이 미리 들어갑니다.
2. 항목을 채웁니다. 입력하는 대로 미리보기가 다시 그려지고, 너무 길거나 필수인데 비어 있는 항목은 보내기 전에 알려 줍니다.
3. **서명된 URL 복사**를 누르거나, **코드** 탭에서 지금 값이 들어간 `@mocco/node` 코드를 복사합니다.

![article 템플릿을 채운 OG 이미지 페이지와 미리보기](https://fi-workers-mocco-storage.s3.ap-northeast-2.amazonaws.com/pub/w/93e11fe8-0494-4e3d-b1cb-fe4dffd3ee7e/p/d64785b8-9a23-4fa1-a81d-550af30e203a/helpcenter/3ce09885-3ee0-4413-a4e5-b9e55ad0d4e7/og-gallery.png)

시크릿이 없으면 페이지에 그렇게 표시됩니다. 소유자와 관리자에게는 시크릿을 만드는 링크가, 다른 멤버에게는 누가 만들 수 있는지가 보입니다.

미리보기는 저장되지 않고 프로젝트의 이미지 한도에도 포함되지 않지만, 한 사람이 1분에 30번까지 그릴 수 있습니다.

## 서버에서 `@mocco/node`로

```js
import { createOgSigner } from '@mocco/node';

const og = createOgSigner({
  projectId: process.env.MOCCO_PROJECT_ID,
  secret: process.env.MOCCO_OG_SECRET,
});

const image = og.url({
  template: 'article',
  params: { brand: 'Acme Docs', eyebrow: 'Guides', title: 'Install in five minutes' },
});
// https://api.mocco.club/v1/og/<project id>/article.png?…&s=…
```

서명은 네트워크 요청 없이 서버에서 이루어지므로, 페이지를 그릴 때마다 하거나 빌드할 때 해도 됩니다. 이미 `createMoccoServer`를 쓰고 있다면 `og: { projectId, secret }`을 넘기고 `server.og.url(…)`을 부르세요. `undefined`로 둔 항목은 빠집니다. 서명 도구는 시크릿과 프로젝트 ID만 확인하고, 항목은 이미지를 불러올 때 Mocco가 확인합니다.

## 다른 언어에서

서명을 직접 만듭니다.

1. `s`를 뺀 모든 항목을 이름순으로 정렬하고, JavaScript의 `encodeURIComponent`처럼 이름과 값을 인코딩해 `name=value` 쌍을 `&`로 잇습니다.
2. `/v1/og/<project id>/<template>.png?<이은 항목>` 문자열을 만듭니다. Mocco API가 다른 호스트나 경로 아래에서 제공되더라도 이 경로를 씁니다.
3. 시크릿(64자 문자열을 UTF-8로)을 키로 이 문자열의 HMAC-SHA256을 구하고, base64url로 인코딩해 앞 32자를 남깁니다. 이것이 `s`입니다.
4. URL 끝에 `&s=<서명>`을 붙입니다. 최종 URL에서 파라미터 순서는 상관없습니다.

```js
import { createHmac } from 'node:crypto';

function ogImageUrl(projectId, template, fields, secret) {
  const path = `/v1/og/${projectId}/${template}.png`;
  const query = Object.keys(fields)
    .sort()
    .map(name => `${encodeURIComponent(name)}=${encodeURIComponent(fields[name])}`)
    .join('&');
  const s = createHmac('sha256', secret).update(`${path}?${query}`).digest('base64url').slice(0, 32);
  return `https://api.mocco.club${path}?${query}&s=${s}`;
}
```

## Mocco의 응답

| 상황 | 응답 |
| --- | --- |
| 없는 템플릿, 또는 서명 시크릿이 없는 프로젝트 | `404` |
| 서명이 없거나 맞지 않음(다른 프로젝트의 시크릿이나 교체 전 시크릿으로 서명한 경우 포함) | `401` |
| 필수 항목이 없거나, 템플릿에 없는 항목, 한도를 넘는 값, 잘못된 `accent` | `400`, 문제가 된 항목을 알려 줌 |
| 프로젝트에서 1분에 새로 그리는 이미지가 60개를 넘음 | `429`, `Retry-After` 포함 |
| 그 밖의 경우 | PNG 이미지, 하루 동안 캐시 |

1분에 60개 한도에는 새로 그리는 경우만 포함됩니다. 한 번 그린 이미지는 같은 URL로 다시 불러오면 저장된 이미지로 제공됩니다. 크롤러가 렌더링을 기다리는 일이 없게 하려면 [CI에서 이미지를 미리 그려 두세요](https://www.mocco.club/docs/ko/articles/irw7vm-pre-render).

항목을 바꾸면 URL이 바뀌고, 그래서 이미지도 바뀝니다. 카카오톡 같은 앱이 이미 캐시한 카드를 새로 고치는 방법도 이것입니다. 이런 앱은 예전 URL을 다시 가져오지 않습니다.
