> ## Documentation Index
> Fetch the complete documentation index at: https://docs.openapi.pluuug.com/llms.txt
> Use this file to discover all available pages before exploring further.

# 🔐 인증 방식

> 플러그 오픈 API는 API Key와 Signature 기반의 인증 방식을 사용합니다.

## 인증 방식 안내

플러그 오픈 API는 **API Key + Signature** 기반의 인증 방식을 사용합니다. 모든 API 요청 시 두 가지 인증 정보를 **반드시 헤더에 포함**해야 합니다.

<AccordionGroup>
  <Accordion title="🧾 인증 헤더 구성" defaultOpen={true}>
    <Info>
      모든 API 요청 시 아래 헤더를 포함해야 합니다.
    </Info>

    * `X-API-KEY`: 발급받은 API Key
    * `X-Signature`: 요청 본문에 대한 HMAC 서명값

    `X-Signature`가 없는 요청은 인증되지 않으며, 서버에서 거부됩니다.
  </Accordion>

  <Accordion title="🔐 Signature 서명 방식" defaultOpen={false}>
    <Info>
      Signature는 API Key 발급 시 함께 제공된 Secret Key를 사용하여 생성합니다.
    </Info>

    * 알고리즘: HMAC-SHA256
    * 서명 대상: 요청 본문 (`request.body`)
    * 서버는 클라이언트가 보낸 Signature가 유효한지 검증합니다.

    Signature는 요청의 무결성을 보장하며, 위변조 방지 목적이 있습니다.
  </Accordion>
</AccordionGroup>

### 💡 언어별 서명 예시

API 요청 시 `request.body`를 기준으로 HMAC-SHA256 서명을 생성합니다.
요청 본문이 없을 경우, 자동으로 빈 문자열(`""`)을 서명 대상으로 처리합니다.

<AccordionGroup>
  <Accordion title="Java (JDK 8 이상)" defaultOpen={false}>
    ```java theme={null}
    import javax.crypto.Mac;
    import javax.crypto.spec.SecretKeySpec;
    import java.nio.charset.StandardCharsets;

    public class HmacSignature {
        public static void main(String[] args) throws Exception {
            String secretKey = "your-secret-key";

            String body = getBody(); // 요청 본문이 있으면 JSON 문자열, 없으면 ""

            Mac sha256_HMAC = Mac.getInstance("HmacSHA256");
            SecretKeySpec secret_key = new SecretKeySpec(secretKey.getBytes(StandardCharsets.UTF_8), "HmacSHA256");
            sha256_HMAC.init(secret_key);

            byte[] hash = sha256_HMAC.doFinal(body.getBytes(StandardCharsets.UTF_8));
            String signature = bytesToHex(hash);

            System.out.println(signature);
        }

        private static String getBody() {
            // 본문이 있을 경우 직렬화된 문자열 반환
            // 없으면 return "";
            return "{\"name\":\"pluuug\",\"type\":\"openapi\"}";
        }

        private static String bytesToHex(byte[] bytes) {
            StringBuilder sb = new StringBuilder();
            for (byte b : bytes) {
                sb.append(String.format("%02x", b));
            }
            return sb.toString();
        }
    }
    ```
  </Accordion>

  <Accordion title="Python (3.6+)" defaultOpen={false}>
    ```python theme={null}
    import json, hmac, hashlib

    payload = {"name": "pluuug", "type": "openapi"}  # 본문이 없으면 None
    body = json.dumps(payload, separators=(",", ":")) if payload else ""

    secret_key = "your-secret-key"
    signature = hmac.new(secret_key.encode(), body.encode(), hashlib.sha256).hexdigest()
    print(signature)
    ```
  </Accordion>

  <Accordion title="JavaScript - 브라우저 (ES2020+)" defaultOpen={false}>
    ```js theme={null}
    const payload = { name: "pluuug", type: "openapi" }; // 없으면 null
    const body = payload ? JSON.stringify(payload) : "";

    async function generateSignature(secretKey, body) {
      const encoder = new TextEncoder();
      const key = await crypto.subtle.importKey(
        "raw",
        encoder.encode(secretKey),
        { name: "HMAC", hash: "SHA-256" },
        false,
        ["sign"]
      );
      const signature = await crypto.subtle.sign("HMAC", key, encoder.encode(body));
      return [...new Uint8Array(signature)]
        .map(b => b.toString(16).padStart(2, "0"))
        .join("");
    }

    generateSignature("your-secret-key", body).then(console.log);
    ```
  </Accordion>

  <Accordion title="Node.js (v14+)" defaultOpen={false}>
    ```js theme={null}
    const crypto = require("crypto");

    const payload = { name: "pluuug", type: "openapi" }; // 없으면 null
    const body = payload ? JSON.stringify(payload) : "";

    const secretKey = "your-secret-key";
    const signature = crypto
      .createHmac("sha256", secretKey)
      .update(body)
      .digest("hex");

    console.log(signature);
    ```
  </Accordion>

  <Accordion title="PHP (7.2+)" defaultOpen={false}>
    ```php theme={null}
    $payload = ['name' => 'pluuug', 'type' => 'openapi']; // 없으면 null
    $body = $payload
      ? json_encode($payload, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE)
      : "";

    $secretKey = 'your-secret-key';
    $signature = hash_hmac('sha256', $body, $secretKey);
    echo $signature;
    ```
  </Accordion>

  <Accordion title="Go (1.16+)" defaultOpen={false}>
    ```go theme={null}
    package main

    import (
        "crypto/hmac"
        "crypto/sha256"
        "encoding/hex"
        "encoding/json"
        "fmt"
    )

    func main() {
        payload := map[string]string{
            "name": "pluuug",
            "type": "openapi",
        }

        var bodyBytes []byte
        if payload != nil {
            bodyBytes, _ = json.Marshal(payload)
        } else {
            bodyBytes = []byte("")
        }

        secretKey := []byte("your-secret-key")
        h := hmac.New(sha256.New, secretKey)
        h.Write(bodyBytes)
        signature := hex.EncodeToString(h.Sum(nil))

        fmt.Println(signature)
    }
    ```
  </Accordion>
</AccordionGroup>
