# 認証

> マイページで発行したクライアントでアクセストークンを取得し、公開 API を呼び出す手順。

公開 API は OAuth 2.0 のクライアントクレデンシャルフローで認証します。マイページで発行した `client_id` と `client_secret` でアクセストークンを取得し、そのトークンを付けて API を呼び出します。ブラウザでの操作や同意画面はありません。

:::note
自社のアカウントから郵便物を送る場合は、このページの手順だけで API を使えます。複数のネットdeゆうびんユーザーの代理で API を呼び出すサービスを提供する場合は、[パートナー向け認証](/partners/authorization-code/)を参照してください。
:::

## 1. クライアントの発行

[ネットdeゆうびん](https://yubin.app/)にログインし、マイページの「APIクライアント」から発行します。名前を付けて発行すると `client_id` と `client_secret` が表示されます。`client_secret` を確認できるのは発行直後のこの画面だけなので、その場で控えてください。

発行にはネットdeゆうびん API 利用規約への同意が必要です。同意のチェックは発行画面に出ます。クライアントは1アカウントにつき5個まで持てます。

`client_secret` を紛失した場合は同じ画面から再発行できます。再発行すると古い `client_secret` はすぐに使えなくなります。

:::caution
`client_secret` はパスワードと同じように扱ってください。ブラウザやスマートフォンアプリなど、利用者の手元で動くプログラムには埋め込まず、サーバー側だけで使ってください。
:::

## 2. アクセストークンの取得

トークンエンドポイントに `client_id` と `client_secret` を送ります。`Authorization` ヘッダーには `client_id:client_secret` を base64 でエンコードした値を `Basic` に続けて付けます（`client_secret_basic`）。

```http
POST https://yubin.app/api/oauth/token
Content-Type: application/x-www-form-urlencoded
Authorization: Basic BASE64(client_id:client_secret)

grant_type=client_credentials&scope=account:read mails:read mails:write
```

curl の場合は `-u` で `Authorization` ヘッダーを組み立てられます。

```sh
curl https://yubin.app/api/oauth/token \
  -u "YOUR_CLIENT_ID:YOUR_CLIENT_SECRET" \
  -d grant_type=client_credentials \
  -d "scope=account:read mails:read mails:write"
```

```json
{
  "access_token": "eyJhbGciOiJSUzI1NiIs...",
  "token_type": "Bearer",
  "expires_in": 3600,
  "scope": "account:read mails:read mails:write"
}
```

## 3. API の呼び出し

取得した `access_token` を `Authorization` ヘッダーに付けて呼び出します。

```http
GET https://api.yubin.app/v1/account
Authorization: Bearer ACCESS_TOKEN
```

トークンは発行したアカウントとして扱われます。ほかのアカウントのデータは参照できません。

## アクセストークンの有効期限

アクセストークンの有効期限は `expires_in` の秒数（1時間）です。リフレッシュトークンは発行されないので、期限が切れたら手順 2 と同じリクエストで取り直してください。

## スコープ

マイページで発行したクライアントには、次のスコープがすべて付きます。

| スコープ       | 内容                                                                                                         |
| -------------- | ------------------------------------------------------------------------------------------------------------ |
| `account:read` | アカウント情報の参照（`GET /v1/account`）                                                                    |
| `mails:read`   | 発送依頼と入稿した PDF の参照（`GET /v1/mails/{mailId}`、`GET /v1/mails/{mailId}/contents/{contentId}/pdf`） |
| `mails:write`  | 発送依頼の作成・確定（`POST /v1/mails`、`POST /v1/mails/{mailId}/confirm`）                                  |

クライアントに許可されていないスコープを要求してもエラーにはならず、そのスコープが黙って落とされたトークンが発行されます。実際に得られたスコープはトークンレスポンスの `scope` で確認してください。

## エンドポイント

| 用途         | URL                                                            |
| ------------ | -------------------------------------------------------------- |
| トークン     | `https://yubin.app/api/oauth/token`                            |
| トークン失効 | `https://yubin.app/api/oauth/token/revocation`                 |
| API          | `https://api.yubin.app/`                                       |
| ディスカバリ | `https://yubin.app/api/oauth/.well-known/openid-configuration` |

オートディスカバリを使用するライブラリを使う場合は issuer に `https://yubin.app/api/oauth` を渡してください。

## トークンの失効

トークン失効エンドポイント（`/token/revocation`）にアクセストークンを送ると失効させられます。

## 認証エラー

アクセストークンの検証はリクエストが API に届く前に行われます。トークンが無い・不正・期限切れの場合は `401`、スコープが足りない場合は `403` が返ります。このときのボディは problem+json ではなく次の形になります。

```json
{ "message": "Unauthorized" }
```

トークンは有効だがアカウントが存在しない場合など、API 本体まで到達したエラーは problem+json で返ります。

```json
{
  "type": "https://docs.yubin.app/problems/account_not_found",
  "title": "The account for this access token no longer exists",
  "status": 404,
  "code": "account_not_found"
}
```

`type` は problem ごとに一意な URI で、参照すると[その problem の解説](/problems/account_not_found/)が読めます。`code` はその URI の末尾と同じ値です。エラー処理の分岐はどちらで行っても構いません。