「OAuth2.0 対応」と聞くと身構えられることがありますが、Bカートの認証において押さえるべき点は3つだけです。
開発ボリュームの大半は、OAuth 部分ではなく自社システムとのデータマッピング側に発生します。
このページについて Bカートアプリの OAuth 認証に必要な情報を1ページに集約しています。 これまで PDF で提供していた「Bカートアプリ アクセストークンの発行方法」の内容も本ページに含まれます。
ポイントは ③でBカート利用者がBカートのログイン情報を入力する先はBカート自身であることです。 御社アプリが利用者のIDやパスワードを預かる必要はありません。これが OAuth を採用している理由です。
関連資料 — アプリのインストール導線や画面要件といったフロントエンド側の仕様は、Bカートアプリストアアプリ開発手順(PDF) にまとめています。
OAuth の実装自体は、全体工数の 1〜2割程度です。
以下は一般的な構成での目安です。実際の工数は、連携する自社システムの複雑さによって変わります。
フェーズ | 内容 | 工数の目安 |
|---|---|---|
① OAuth 認証まわり | 認可導線の実装/トークンの保管/自動リフレッシュ処理 | 3〜5人日 |
② API 連携ロジック | 受注データの取得、自社システムへの投入、項目マッピング、エラー処理 | 要件次第(ここが大半) |
③ アプリストア公開対応 | アイコン・説明文・スクリーンショットの準備、デモアカウント用意、審査対応 | 1〜2人日 |
「認可URLに飛ばす → コードを受け取る → トークンに交換する」だけなら、実装は半日から1日で終わります。 残りは以下の運用設計に充てられます。
この3点は後から足すのが難しいため、最初に設計へ織り込んでおきます。 アクセストークンの有効期限には十分ご留意下さい。
アクセストークンの有効期限は14日間となっています。有効期限を保存し、切れる前に更新する定期バッチを用意するようにしましょう。
リフレッシュトークンには有効期限はありませんが、アクセストークンの更新時には新たなリフレッシュトークンで保存するように気をつけましょう。
更新レスポンスを受け取った後、新しいリフレッシュトークンの保存に失敗すると、 古いトークンは既に無効なため、認可のやり直しが必要です。
保存に失敗した場合は、利用者に再認可を促す導線(再連携ボタンと案内メール等)を用意しておくようにしましょう。
redirect_uri は完全一致デベロッパーサイトで登録した値と、認可リクエスト・トークンリクエストで渡す値が完全に一致する必要があります。 末尾のスラッシュの有無、http/https の違い、ポート番号の有無、いずれも不一致の原因になります。
対策: 定数として1箇所に定義し、全リクエストで同じ値を参照します。
state の未実装state は仕様上は任意です。ただし未実装だと CSRF 攻撃によって、 攻撃者のBカートアカウントが被害者のアプリアカウントに紐づけられるリスクが生じます。
対策: セッションに乱数を保存し、コールバック時に照合します。実装コストは数行です。
実装に入る前に、以下2点が必要です。
ご注意: 無料トライアルサイトからは、アプリストアアプリ公開用のデベロッパーサイトアカウントは発行できません。
準備が整ったら、デベロッパーサイト にログインし、 サイドメニューの 「アプリストア アプリ管理」 から OAuth クライアントを作成します。
作成時に入力する項目:
項目 | 説明 |
|---|---|
クライアント名 | OAuth クライアントの識別名。利用者には表示されないため、管理しやすい名前で構いません |
リダイレクトURI | 認証後に戻ってくる御社アプリ側のURL。完全一致で検証されます(→ 3章④) |
作成すると クライアントID と クライアントシークレット が自動発行されます。 一覧の虫眼鏡アイコンから確認できます。
関連資料 — 開発の始め方全体は アプリストア アプリ開発スタートガイド、アカウント発行の画面手順は PDF資料 をご覧ください。
御社アプリの連携ページなどから、以下のURLへ利用者をリダイレクトさせます。
認可エンドポイント
https://app.bcart.jp/oauth/authorize
リクエストパラメータ(GET)
パラメータ | 必須 | 説明 | 値の例 |
|---|---|---|---|
| ○ | 発行されたクライアントID |
|
| ○ | 固定値 |
|
| ○ | 登録済みのリダイレクトURI |
|
| ○ | 利用するAPIのアクセス権。スペース区切りで複数指定 |
|
| 任意 | CSRF対策用の任意文字列。レスポンスにそのまま返却されます。実装を推奨します |
|
組み立て例
https://app.bcart.jp/oauth/authorize?client_id=95941eef-e310-4a9c-9b56-8bdf26ef8bdf&response_type=code&redirect_uri=https%3A%2F%2Fexample.app%2Fcallback&scope=products-read%20products-write%20customers-read&state=6202367c31f31
このページで利用者にBカートへのログインが求められ、続いて御社アプリが要求したスコープを 許可するかどうかの確認画面が表示されます。
許可された場合 — code クエリパラメータに認可コードが付与されてリダイレクトされます。
https://example.app/callback?code=def50200ad47270…&state=6202367c31f31
キャンセル/エラーの場合 — error クエリパラメータが付与されます。
https://example.app/callback?error=access_denied&state=6202367c31f31
認可コードの有効期限は発行から10分間です。 受け取ったらすぐに次のステップへ進んでください。
受け取った認可コードを、サーバーサイドから以下のエンドポイントへ POST します。 クライアントシークレットを使うため、必ずサーバー間通信で行ってください(ブラウザから実行しない)。
トークンエンドポイント
POST https://app.bcart.jp/oauth/token
リクエストパラメータ(POST)
パラメータ | 説明 |
|---|---|
| 固定値 |
| クライアントID |
| クライアントシークレット |
| 登録済みのリダイレクトURI(認可時と同一の値) |
| 5-1 で取得した認可コード |
成功レスポンス
{
"token_type": "Bearer",
"expires_in": 1209600,
"access_token": "eyJ0eXAiOiJKV1QiLCJhbG…",
"refresh_token": "def502006bbe5a47fcf453…"
}
フィールド | 説明 |
|---|---|
|
|
| アクセストークンが無効になるまでの秒数。1209600秒=14日間 |
| API 呼び出しに使用するアクセストークン |
| アクセストークンを更新するためのリフレッシュトークン |
エラーレスポンス
{
"error": "invalid_request",
"error_description": "The request is missing a …",
"hint": "Cannot decrypt the …",
"message": "The request is missing a …"
}
デバッグのコツ
error_descriptionとmessageは汎用的な定型文のため、原因の切り分けには使えません。 具体的な原因はhintに入ります(例:Failed to verify code_verifier.、Authorization code has been revoked)。 まずhintを確認してください。
アクセストークンは14日で失効します。期限が切れる前に、リフレッシュトークンを使って新しいアクセストークンを取得します。 リフレッシュトークン自体に有効期限はありません。
エンドポイント(5-2 と同じ)
POST https://app.bcart.jp/oauth/token
リクエストパラメータ(POST)
パラメータ | 説明 |
|---|---|
| 固定値 |
| 保管しているリフレッシュトークン |
| クライアントID |
| クライアントシークレット |
成功レスポンス(5-2 と同じ形式。新しいリフレッシュトークンが含まれます)
{
"token_type": "Bearer",
"expires_in": 1209600,
"access_token": "eyJ0eXAiYasieQiLHIde…",
"refresh_token": "def5020sde47fcf4dsad…"
}
つまり、更新のたびに保存し直す設計が前提になります。 並行処理が同時に更新を走らせた場合の対策は「3. 実装前に押さえる5つの落とし穴」①で解説しています。
言語非依存の最小構成です。実際にはお使いの言語の OAuth クライアントライブラリの利用を推奨します。
function startConnect(tenant):
state = generateRandomString()
session.save("oauth_state", state)
url = "https://app.bcart.jp/oauth/authorize"
+ "?client_id=" + CLIENT_ID
+ "&response_type=code"
+ "&redirect_uri=" + urlencode(REDIRECT_URI)
+ "&scope=" + urlencode("orders-read products-read")
+ "&state=" + state
redirect(url)
function handleCallback(request):
if request.query["error"] exists:
showError(request.query["error"])
return
if request.query["state"] != session.get("oauth_state"):
abort("state mismatch") // CSRF の可能性
response = httpPost("https://app.bcart.jp/oauth/token", {
grant_type: "authorization_code",
client_id: CLIENT_ID,
client_secret: CLIENT_SECRET,
redirect_uri: REDIRECT_URI,
code: request.query["code"]
})
saveTokens(
tenantId,
response.access_token,
response.refresh_token,
now() + response.expires_in // 有効期限を保存
)
function refreshToken(tenantId):
lock = acquireLock("oauth:" + tenantId) // ★ 排他制御が必須
if not lock:
return // 別処理が更新中
try:
current = loadTokens(tenantId)
response = httpPost("https://app.bcart.jp/oauth/token", {
grant_type: "refresh_token",
refresh_token: current.refresh_token,
client_id: CLIENT_ID,
client_secret: CLIENT_SECRET
})
// ★ 新しい refresh_token を必ず保存する
saveTokens(
tenantId,
response.access_token,
response.refresh_token,
now() + response.expires_in
)
catch error:
markReauthRequired(tenantId) // ★ 再認可導線へ誘導
notifyAdmin(tenantId, error)
finally:
releaseLock(lock)
// 例:1日1回実行
function dailyRefreshJob():
tenants = findTenantsWhere(expiresAt < now() + 7days)
for tenant in tenants:
refreshToken(tenant.id)
scope パラメータには、以下からアプリで必要な機能をスペース区切りで指定します。 各機能の詳細は APIドキュメント をご確認ください。
選ぶスコープは必要最小限に絞ってください。ここで要求した権限は、認可画面で右列の日本語名のまま利用者に表示されます (orders-read なら「受注参照」)。過剰な要求は許可率を下げますし、公開審査でも指摘の対象になります。
スコープ | 機能 |
|---|---|
| 商品参照 |
| 商品書込み |
| 商品カスタム参照 |
| 商品セット参照 |
| 商品セット書込み |
| 商品オプション参照 |
| 商品セットカスタム参照 |
| 在庫参照 |
| 在庫書込み |
| 商品カテゴリ参照 |
| 商品カテゴリ書込み |
| 会員参照 |
| 会員書込み |
| 会員カスタム参照 |
| 別配送先参照 |
| 別配送先書込み |
| 注文状況参照 |
| 注文状況書込み |
| 受注参照 |
| 受注書込み |
| 受注商品参照 |
| 受注商品書込み |
| 受注カスタム参照 |
| 出荷参照 |
| 出荷書込み |
| 価格グループ参照 |
| 表示グループ参照 |
| 配送グループ参照 |
| 製品の特徴参照 |
| 製品の特徴書込み |
| お気に入り参照 |
| お気に入り書込み |
| ポイント参照 |
| ポイント書込み |
Q. OAuth ライブラリは何を使えばよいですか? A. 特定のライブラリの指定はありません。Authorization Code Grant に対応した標準的なクライアントであれば どれでも動作します。多くのライブラリが PKCE をデフォルトで有効にしていますが、そのままでも問題ありません(次項参照)。
Q. PKCE には対応していますか? A. 対応しています。 code_challenge / code_verifier を用いた実装が可能です。 PKCE を必須とする設定のライブラリでも、そのままご利用いただけます。
項目 | 対応状況 |
|---|---|
|
|
PKCE の要否 | 任意。 |
| トークン交換時に照合されます(不一致の場合 |
セキュリティ上、plain ではなく S256 をお使いください。
PKCE を使う場合も、トークン交換時に client_secret は必要です。 つまり PKCE を導入しても、クライアントサイド(SPA・モバイルアプリ単体)で完結する実装はできません。 client_secret を秘匿できるサーバーサイドでトークン交換を行う構成は、PKCE の有無にかかわらず必須です。
サーバーサイドで完結する一般的な構成であれば、PKCE を無理に導入する必要はありません。
Q. 検証環境はどうやって用意しますか? A. Bカートパートナープログラム にご登録いただくと、 検証用のデモ環境が発行されます。無料トライアルサイトではアプリストア用アカウントを発行できないためご注意ください。
Q. API の利用に料金はかかりますか? A. API は無料でご利用いただけます。アプリの公開も現時点では無料です (今後、有料アプリに対応する際は手数料が発生する可能性があります)。
Q. アクセストークンが切れたらどうなりますか? A. API 呼び出しが失敗します。リフレッシュトークンには有効期限がないため、 リフレッシュトークンさえ保持していれば再認可なしで復旧できます。 逆にリフレッシュトークンを失うと、利用者に再度認可してもらう必要があります。
Q. プライベートアプリとの使い分けは? A. 特定の1社にのみ提供する連携であれば、プライベートアプリ が適しています。 OAuth フローが不要で、Bカート管理画面から発行したトークンをそのまま使え、トークンは無期限です。 不特定多数のBカート利用者へ提供する場合はアプリストアアプリ(=本ガイドの OAuth 方式)を選択してください。
アプリストアアプリ | プライベートアプリ | |
|---|---|---|
認証方式 | OAuth2.0 認可コードフロー | 発行済みトークン |
トークン有効期限 | 14日(リフレッシュで更新) | 無期限 |
対象 | 不特定多数のBカート利用者 | 契約中の特定1社 |
公開審査 | 必要 | 不要 |
Q. アプリを特定の利用者にのみ提供したい場合は? A. アプリストアに未公開であれば第三者は利用できません。 その用途では、利用者側で発行したプライベートアプリのアクセストークンをお使いください。 なお、アプリ利用者からアプリ提供者へアプリストアアカウントを発行することは推奨していません。
関連資料 — 本ページに載っていないご質問は よくある質問 をご確認ください。
実装でご不明な点は お問い合わせフォーム からご連絡ください。
