# 認証

## 概要

Sora Cloud では、JWT 形式のアクセストークンを利用して認証を行います。

Sora の `"type": "connect"` メッセージ送信時に、 `metadata` の `access_token` にアクセストークンを設定してください。

## metadata

`type: connect` の `metadata` に `"access_token": "<JWT>"` を含めます。

```json
{
    "type": "connect",
    "role": "sendrecv",
    "channel_id": "sora-cloud@shiguredo#1490",
    "multistream": "true",
    "metadata": {
        "access_token": "<JWT>"
    }
}
```

## JWT 仕様

**typ**: JWT
**alg**: HS256

## JWT 利用の注意点

Sora Cloud では利用する特定のアクセストークンを失効させる機能はなく、失効が必要な場合は API キーを再生成するしかありません。
そのため、本番環境向けには必ず `nbf` / `exp` を付けて短い時間しか利用できないトークンを発行するようにしてください。

Sora Cloud の認証では、JWT で利用可能なクレームは、次の [利用可能な登録済みクレーム](auth.html#7888a8) のみです。

認証ウェブフックを設定し、プロジェクト側でのチェックを行うようにしてください。


## 利用可能な登録済みクレーム

### exp

**クレーム**: exp
**型**: integer
**要求**: オプション
**RFC**: [4.1.4.  "exp" (Expiration Time) Claim](https://www.rfc-editor.org/rfc/rfc7519.html#section-4.1.4)

トークンが利用できなくなる時間 (UTC) を指定できます。

### nbf

**クレーム**: nbf
**型**: integer
**要求**: オプション
**RFC**: [4.1.5.  "nbf" (Not Before) Claim](https://www.rfc-editor.org/rfc/rfc7519.html#section-4.1.5)

トークンが利用できるようになる時間 (UTC) を指定できます。










### jti

**クレーム**: jti
**型**: string
**要求**: オプション

## オプションプライベートクレーム

### channel_id

> **危険**
>
> `channel_id クレーム` を指定しない場合、すべてのチャネルにアクセス可能になるため、本番環境では `channel_id クレーム` を指定してください。

**クレーム**: channel_id
**型**: string
**要求**: オプション

channel_id クレームが含まれていた場合、Sora Cloud が認証時に channel_id と一致しているかどうかを確認します。

### role

**クレーム**: role
**型**: string
**要求**: オプション

role クレームが含まれていた場合、Sora Cloud が認証時に role と一致しているかどうかを確認します。

指定可能な文字列は sendrecv / recvonly / sendonly です。

### max_channel_connections

**クレーム**: max_channel_connections
**型**: integer
**要求**: オプション

認証時にチェックするチャネルの最大接続数を指定できます。

## JWT 生成例

プロジェクトの API キーを署名鍵として JWT を生成し、必要に応じて `channel_id`、 `role`、 `exp`、 `nbf`、 `jti` などのクレームを設定してください。

以下に、Python / Go でアクセストークンを生成する最小の例を示します。用途に応じて必要なクレームを追加してください。

### Python

`PyJWT` を利用する例です。

```python
import datetime
import uuid

import jwt

api_key = "YOUR_API_KEY"
now = datetime.datetime.now(datetime.timezone.utc)

payload = {
    "channel_id": "example-channel@YOUR_PROJECT_ID",
    "role": "sendrecv",
    "nbf": int(now.timestamp()),
    "exp": int((now + datetime.timedelta(minutes=30)).timestamp()),
    "jti": str(uuid.uuid4()),
}

access_token = jwt.encode(payload, api_key, algorithm="HS256")
print(access_token)
```

### Go

`github.com/golang-jwt/jwt/v5` を利用する例です。

```go
package main

import (
    "fmt"
    "time"

    "github.com/golang-jwt/jwt/v5"
    "github.com/google/uuid"
)

func main() {
    apiKey := "YOUR_API_KEY"
    now := time.Now().UTC()

    claims := jwt.MapClaims{
        "channel_id": "example-channel@YOUR_PROJECT_ID",
        "role":       "sendrecv",
        "nbf":        now.Unix(),
        "exp":        now.Add(30 * time.Minute).Unix(),
        "jti":        uuid.NewString(),
    }

    token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
    accessToken, err := token.SignedString([]byte(apiKey))
    if err != nil {
        panic(err)
    }

    fmt.Println(accessToken)
}
```

## 参考

- [RFC 7519: JSON Web Token (JWT)](https://www.rfc-editor.org/rfc/rfc7519.html)
- [JSON Web Token (JWT)](https://www.iana.org/assignments/jwt/jwt.xhtml)
- [JSON Web Tokens - jwt.io](https://jwt.io/)

## シーケンス図

### アクセストークンでの認証成功

- アクセストークン生成 API 利用あり
- Sora 認証ウェブフックの設定あり

```mermaid
sequenceDiagram
   autonumber
   participant client as クライアント
   participant sora as WebRTC SFU Sora
   participant cloud as Sora Cloud
   participant app as アプリケーションサーバー
   app->>cloud: アクセストークン API<br>
   cloud-->>app: 200 OK<br>"access_token": "<JWT>"
   app->>client: Sora Cloud 認証用の JWT 払い出し
   client->>sora: "type": "connect"<br>"metadata": {"access_token": "<JWT>"}
   sora->>cloud: 認証ウェブフック
   note over cloud: アクセストークン検証成功
   cloud->>app: 認証ウェブフック
   app-->>cloud: 200 OK<br>"allowed": true
   cloud-->>sora: 200 OK<br>"allowed": true
   sora->>client: "type": "offer"
   client->>sora: "type": "answer"
   note over client,sora: WebRTC 確立
```
























