API認証ガイド
レシートローラー API は OAuth 2.0 の認可コードフローで認証します。開発者がアプリを登録し、ビジネスアカウントのオーナーが同意画面で許可すると、アプリは認可コードをアクセストークンに交換して API を呼び出せます。この記事では、認可URLのパラメーター、同意画面の動き、トークンの交換・取り消し、返るエラー、使えるスコープをまとめます。最初の1回を手を動かして試したい場合ははじめてのAPI呼び出しから始めてください。
全体の流れ
- 開発者アプリを登録し、クライアントIDとクライアントシークレットを受け取る
- ユーザーのブラウザを
https://receiptroller.io/oauth/authorizeに送る - ユーザーが同意画面で「許可する」を押すと、登録済みのリダイレクトURIに
codeとstateが付いて戻る - サーバーから
POST https://receiptroller.io/api/v1/auth/tokenでcodeをアクセストークンとリフレッシュトークンに交換する Authorization: Bearer {アクセストークン}を付けて API を呼ぶ- 期限が近づいたらリフレッシュトークンで更新する
アプリを登録する
アプリの登録はビジネスアカウントのオーナーが行います。ビジネスアカウントのプランがスタータープラン以上である必要があります。手順と入力項目はアプリを新規作成するをご覧ください。登録できるリダイレクトURIは1アプリにつき1つです。
認可画面へ送る
GET https://receiptroller.io/oauth/authorize
?response_type=code
&client_id=YOUR_CLIENT_ID
&redirect_uri=https%3A%2F%2Fexample.com%2Fcallback
&scope=store.products.read%20store.orders.read
&state=RANDOM_STATE
&code_challenge=CODE_CHALLENGE
&code_challenge_method=S256
| パラメーター | 必須 | 説明 |
|---|---|---|
response_type | はい | code のみ使えます。 |
client_id | はい | アプリのクライアントID。 |
redirect_uri | はい | アプリに登録したURIと1文字も違わない値。 |
scope | はい | スペース区切りのスコープ。アプリに登録したスコープだけが許可されます。 |
state | 推奨 | CSRF 対策のランダムな文字列。コールバックにそのまま付いて戻ります。 |
code_challenge | 公開クライアントは必須 | PKCE のチャレンジ。S256 では code_verifier の SHA-256 を Base64URL(末尾の = なし)にした値です。 |
code_challenge_method | 任意 | S256 を指定してください。省略すると plain として扱います。S256 と plain 以外(s256 のような大文字・小文字の違いを含む)は invalid_request になります。 |
prompt | 任意 | login を指定すると、ログイン中のセッションを破棄してサインインからやり直させます。 |
identity_provider | 任意 | 未ログインのユーザーを、ログイン画面を飛ばして指定のサインイン方法へ直接送ります(google、microsoft、apple、line、smaregi)。acr_values=idp:google の形でも指定できます。 |
未ログインのユーザーは、まずレシートローラーのログイン画面に送られ、ログイン後に同意画面へ戻ります。
同意画面とビジネスアカウントの選択
同意画面の動きは、アプリの「認可時に1つのビジネスアカウントへトークンを紐付ける」の設定で変わります。
- オン(既定): 同意画面でビジネスアカウントを1つ選びます。選べるのは、ログイン中のユーザーがオーナーであるビジネスアカウントだけです。発行されるトークンはそのビジネスアカウントに紐付き、ユーザー個人は含まれません。そのため
/api/v1/meと/api/v1/me/organizationsは 403 を返します。API 呼び出しでorganizationIdは省略でき、別のビジネスアカウントを指定すると 403 になります。 - オフ: ビジネスアカウントは選びません。トークンはユーザー本人のもので、API を呼ぶたびに
organizationIdを付けます。サーバーは呼び出しごとに、そのユーザーがビジネスアカウントのメンバーかを確認します。複数のビジネスアカウントを切り替えるモバイルアプリ向けです(ネイティブモバイルアプリ向けガイド)。
同意画面では要求されたスコープがチェック済みで並び、ユーザーは外すこともできます。プランがスタータープラン未満のビジネスアカウントは、プランの変更が必要と表示され、そのビジネスアカウントでは許可できません。同じアプリ・同じスコープに一度同意済みの場合、同意画面を出さずにすぐリダイレクトします。
コールバックを受け取る
許可されると、登録したリダイレクトURIに戻ります。
https://example.com/callback?code=AUTHORIZATION_CODE&state=RANDOM_STATE
拒否された場合や、ユーザーがすべてのスコープを外した場合は次のように戻ります。
https://example.com/callback?error=access_denied&state=RANDOM_STATE
https://example.com/callback?error=access_denied&error_description=no_scopes_approved&state=RANDOM_STATE
認可コードの有効期限は10分で、一度しか使えません。state は送った値と一致するか必ず確認してください。
認可画面で返るエラー
次のエラーはリダイレクトせず、ブラウザに HTTP 400 の JSON(error、一部は error_description)を表示します。
| error | 原因 |
|---|---|
unsupported_response_type | response_type が code ではない |
invalid_client | client_id が存在しない、またはアプリが無効になっている |
invalid_redirect_uri | redirect_uri が登録値と一致しない、またはアプリにリダイレクトURIが登録されていない |
invalid_scope | scope がない、または紐付けオンのアプリが user.* とそれ以外のスコープを1回の要求に混ぜた |
invalid_request | code_challenge_method が S256 でも plain でもない |
app_not_approved | アプリが user.* を要求したが、アプリの審査が承認されていない(紐付けの設定にかかわらず) |
no_organization | 紐付けオンのアプリで、ログイン中のユーザーがオーナーであるビジネスアカウントがない |
認可コードをトークンに交換する
サーバー側から送ります。本文は application/x-www-form-urlencoded を推奨します(JSON も受け付けます)。
POST https://receiptroller.io/api/v1/auth/token
Content-Type: application/x-www-form-urlencoded
grant_type=authorization_code
&code=AUTHORIZATION_CODE
&redirect_uri=https%3A%2F%2Fexample.com%2Fcallback
&client_id=YOUR_CLIENT_ID
&client_secret=YOUR_CLIENT_SECRET
&code_verifier=CODE_VERIFIER
redirect_uriは認可リクエストと同じ値にします。client_secretは本文に入れます。Authorizationヘッダーの Basic 認証は読み取りません。公開クライアントはclient_secretを送りません。- 認可リクエストで
code_challengeを送った場合はcode_verifierが必須です。公開クライアントは PKCE なしで発行されたコードを交換できません。
成功すると 200 が返ります。
{
"access_token": "…",
"refresh_token": "…",
"token_type": "Bearer",
"expires_in": 28800,
"scope": "store.products.read store.orders.read",
"accessToken": "…",
"refreshToken": "…",
"tokenType": "Bearer",
"expiresIn": 28800
}
accessToken などの camelCase のキーは、古いクライアント向けに同じ値を重ねて返しているものです。新しく作るアプリは snake_case のキーを読んでください。scope には実際に許可されたスコープが入るので、要求したものと比べてください。有効期限と更新はアクセストークンの取得と更新で説明します。
トークンエンドポイントのエラー
| HTTP | error | 原因 |
|---|---|---|
| 400 | invalid_request | 本文を読み取れない、または code / refresh_token がない |
| 400 | unsupported_grant_type | grant_type が authorization_code / refresh_token 以外(client_credentials は使えません) |
| 401 | invalid_client | クライアントIDが存在しない、またはクライアントシークレットが違う |
| 401 | invalid_grant | コードが無効・期限切れ・使用済み、redirect_uri の不一致、別アプリのコード、PKCE の失敗、リフレッシュトークンの無効・期限切れ、ビジネスアカウントのプランがスタータープラン未満 |
invalid_grant も 401 で返ります。原因は error_description で確認できます。切り分け方はトークンが取得できない(認証エラー)をご覧ください。
API を呼び出す
GET https://receiptroller.io/api/v1/products
Authorization: Bearer ACCESS_TOKEN
紐付けオフのアプリは ?organizationId= を付けます。トークンがない・無効・期限切れのときは 401、必要なスコープがないときは 403 が返ります。
トークンの状態を確かめる
POST https://receiptroller.io/api/v1/auth/verify
Content-Type: application/json
{ "accessToken": "ACCESS_TOKEN" }
有効なら 200 で active、clientId、scope、expiresAt、organizationId(紐付けオフのトークンは null)が返ります。無効なら 401 です。
トークンを取り消す
POST https://receiptroller.io/api/v1/auth/revoke
Content-Type: application/json
{ "token": "ACCESS_OR_REFRESH_TOKEN", "clientId": "YOUR_CLIENT_ID" }
アクセストークンとリフレッシュトークンのどちらを渡しても、その組がまとめて無効になります。成功すると 200 で {"revoked": true}、該当するトークンがないか別のアプリのトークンなら 400 で {"error": "invalid_token"} が返ります。ビジネスアカウントのオーナーは、ビジネスアカウント詳細のメニューにある「連携アプリ」からアプリの連携を取り消せます。取り消すと、そのビジネスアカウントに対するアプリのトークンはすべて無効になります。
スコープ
アプリに登録したスコープの中から、認可リクエストで必要なものを要求します。user.* のスコープはアプリの審査が必要です(User系スコープの審査申請)。
| 分類 | スコープ |
|---|---|
| Store | store.products.read store.products.write store.orders.read store.orders.write store.customers.read store.customers.write store.coupons.read store.coupons.write store.coupons.redeem store.inventory.read store.inventory.write store.flyers.read store.flyers.write store.posts.read store.posts.write store.staff.read store.staff.write store.business-hours.read store.business-hours.write store.reservations.read store.reservations.write store.memberships.read store.memberships.write store.passes.read store.passes.write store.terminal.write store.timecards.read store.timecards.write store.info.read store.info.write store.media.read store.media.write |
| Advertiser | advertiser.campaigns.read advertiser.campaigns.write advertiser.reports.read |
| Media | media.channels.read media.channels.write |
| CRM | crm.profiles.read crm.segments.read |
| SNS | sns.content.read sns.content.write sns.audience.read |
| Analytics | analytics.read sales.read |
| User(審査が必要) | user.profile.read user.profile.write user.receipts.read user.receipts.write user.spending.read user.spending.write user.coupons.read user.coupons.write user.favorites.read user.favorites.write |
各スコープの内容はOAuthスコープ一覧と利用可否をご覧ください。
セキュリティのポイント
client_secretはサーバー側だけで保管します。モバイルアプリなど配布するアプリは「公開クライアント」にして、シークレットの代わりに PKCE を使ってください。stateはリクエストごとに生成し、コールバックで一致を確認してください。- PKCE は
S256を使ってください。 - アクセストークンをログや URL に含めないでください。
- アプリが実際に使うスコープだけを要求してください。