Skip to content

OAuth 2.0 完全接続ガイド

本ドキュメントは、Hamオープンプラットフォームに接続を希望するサードパーティアプリケーション開発者向けです。HamがOAuth 2.0 Authorization Code Grant(RFC 6749 §4.1)に基づいて実装したSSO認可フロー、API仕様、接続の詳細、およびセキュリティベストプラクティスを体系的に紹介します。

  • オープンプラットフォームAPIドメインhttps://open-api.ham.nowcent.cn(すべてのサーバー間HTTP呼び出しはこのドメインを使用、HTTPS必須)
  • 認可エントリ(Universal Link)https://ham.nowcent.cn/sso-authorize?client_id=xxx&scope=profile,is_student&state=yyy&redirect_uri={redirect_uri}

1. 基本概念と役割定義

Hamオープンプラットフォームは標準の OAuth 2.0 Authorization Code Grant(RFC 6749 §4.1)を実装しています。Hamの認可確認UIはモバイルネイティブ認可、デスクトップQRコードスキャン、Passkey認証など複数の方式に対応しており、フロー全体に4つの役割が存在します。

1.1 4つの役割

役割担当責務
リソースオーナーHamログインユーザー保護されたリソース(個人情報、学生身分等)を所有。サードパーティアプリへのアクセスを認可するかどうかを決定
クライアントサードパーティアプリ(Web / App / サーバー)本ドキュメントの対象。認可リクエストの発行、codeの受信、サーバーサイドでのaccess_token取得、UserInfo APIの呼び出し
認可UIHamサードパーティからのDeep Linkを受信し、認可同意ページを表示。モバイルネイティブ認可、デスクトップQRコードスキャン、Passkey認証に対応
認可/リソースサーバーHamバックエンド(open-api.ham.nowcent.cn認可コード・Access Tokenの発行、サードパーティ認証情報の検証、scopeに基づくユーザーリソースの返却

役割間の相互作用(サードパーティ視点):

1.2 主要用語

用語説明
Client IDclient_idHamオープンプラットフォーム登録後に取得する公開識別子
Client Secretclient_secret登録後に取得する機密認証情報サーバーサイドのみで保持し、フロントエンドコード、モバイルバンドル、公開リポジトリには絶対に含めない
Redirect URI認可完了後にHamがリダイレクトするアドレス。Hamオープンプラットフォームコンソールでホワイトリスト登録が必要。完全文字列一致で検証
Authorization CodecodeAccess Token取得用のワンタイム・短期有効な中間認証情報。有効期間5分
Access Tokenユーザー情報アクセス用のBearerトークン。有効期間2時間。Refresh Tokenなし(期限切れ後は再認可が必要)
Scope認可範囲、1.3を参照
Stateクライアントが生成する予測不可能なランダム文字列。CSRF攻撃防止用。リダイレクトURLでそのまま返却
open_id現在のサードパーティアプリにおけるユーザーの安定した一意識別子。決定的(同一ユーザー+同一アプリ=常に同じ)、不可逆アプリ間で異なる

1.3 スコープ権限

Hamオープンプラットフォームが現在サポートするスコープ。最小権限の原則に従い、業務に必要な権限のみを申請してください:

スコープ説明UserInfo返却フィールド
profileニックネームとアバターにアクセスnicknameavatar_url
is_student学生かどうかにアクセスis_student(bool)

注意:リストにないスコープはサーバーで静かにフィルタリングされます。open_idは常に返却され、追加のスコープは不要です。

2. 認可コードフローの詳細

2.1 シーケンス図

2.2 ステップごとの説明

Phase 1 — サードパーティが認可を開始

  1. ユーザーがサードパーティアプリで「Hamでログイン」をクリック。

  2. サードパーティアプリが自身のサーバーで生成:

    • state:予測不可能なランダム文字列(推奨 ≥ 32バイトのエントロピー)、現在のユーザーセッションに紐付けて保存(Session / Redis)。
    • 使用するredirect_uriを選択:Hamオープンプラットフォームコンソールに登録済みのホワイトリストアドレスの1つ、HTTPSのみ。
  3. サードパーティアプリがUniversal Link経由でHamを起動:

    https://ham.nowcent.cn/sso-authorize?client_id=xxx&scope=profile,is_student&state=yyy&redirect_uri={redirect_uri}

Phase 2 — ユーザーがHamで認可

  1. Hamはユーザーのログインを要求し、サードパーティアプリ名、アイコン、リクエストされたスコープ一覧を表示。
  2. ユーザーがHamで「同意」をタップ。同一アプリの同一スコープを以前に認可済みの場合、Hamは同意ページをスキップ可能。

Phase 3 — サードパーティにリダイレクト

  1. Hamバックエンドがredirect_uriがアプリのホワイトリスト内にあることを検証。成功後、Hamがそのアドレスを開き、クエリパラメータにcodeと元のstateを付与:

    {redirect_uri}?code={code}&state={state}

Phase 4 — サーバーがAccess Tokenを交換

  1. サードパーティアプリがredirect_uricodestateを受信:
    • 必ずstateがセッション値と厳密に一致することを検証;
    • codeを直ちに自身のサーバーに送信。
  2. サードパーティサーバーhttps://open-api.ham.nowcent.cn/oauth/tokenにPOSTリクエストを送信し、クライアント認証情報でAccess Tokenを交換。

Phase 5 — サーバーがユーザー情報を取得

  1. サードパーティサーバーBearer {access_token} + クライアント認証情報でhttps://open-api.ham.nowcent.cn/oauth/userinfoをリクエスト。
  2. サードパーティがopen_idをユーザー一意識別子として使用し、ログイン/紐付けなどのビジネスロジックを完了。

3. コア操作の説明

3.1 認可リクエストの構築(Hamの起動)

Universal Linkフォーマット:

https://ham.nowcent.cn/sso-authorize?client_id={client_id}&scope={scopes}&state={state}&redirect_uri={redirect_uri}

パラメータ:

パラメータ必須説明
client_id必須登録時に取得したClient ID
scope必須カンマ区切り、例:profile,is_student
state強く推奨CSRF防御用ランダム文字列、ユーザーセッションに紐付け
redirect_uri必須認可成功後のリダイレクト先。コンソールでホワイトリスト登録済みであること。クエリ文字列に含める際はパーセントエンコーディングが必要

Web例:

html
<a href="https://ham.nowcent.cn/sso-authorize?client_id=abc123&scope=profile,is_student&state=xY7Kq9fZ2pLmN8vB&redirect_uri=https%3A%2F%2Fyour-app.example.com%2Fcallback">
  Hamでログイン
</a>

JS例:

js
const state = crypto.randomUUID();
sessionStorage.setItem('ham_oauth_state', state);
const redirectUri = 'https://your-app.example.com/callback';
const params = new URLSearchParams({
  client_id: 'abc123',
  scope: 'profile,is_student',
  state,
  redirect_uri: redirectUri,
});
location.href = `https://ham.nowcent.cn/sso-authorize?${params.toString()}`;

3.2 認可コールバックの処理

成功リダイレクト:

https://your-app.example.com/callback?code=SplxlOBeZQQYbYS6WxSbIA&state=xY7Kq9fZ2pLmN8vB

ユーザーキャンセル/認可失敗:Hamはリダイレクトしません。サードパーティは「再試行」ログインエントリを保持すべきです。

クライアント処理のポイント:

  1. まずstateがセッション値と厳密に一致することを検証。一致しない場合は終了しエラーを表示;
  2. 検証後のみ、codeを直ちにサーバーに送信してトークン交換;
  3. codeをフロントエンドログ、URLブックマーク、Referrer、フロントエンドストレージに保存しない

3.3 トークン交換(Code → Access Token)

エンドポイント:

POST https://open-api.ham.nowcent.cn/oauth/token

リクエストヘッダー:

Content-Type: application/x-www-form-urlencoded
Authorization: Basic {BASE64(client_id:client_secret)}

リクエストボディ:

パラメータ必須説明
grant_typeはいauthorization_code固定
codeはいPhase 3で取得した認可コード
client_id条件付きBasic Auth未使用時に必須
client_secret条件付きBasic Auth未使用時に必須

成功レスポンス(200 OK):

json
{
  "access_token": "a1b2c3d4e5f6...",
  "token_type": "Bearer",
  "expires_in": 7200,
  "scope": "profile is_student"
}

エラーレスポンス:

json
{
  "error": "invalid_grant",
  "error_description": "The authorization code is invalid or expired"
}

cURL例:

bash
curl -X POST https://open-api.ham.nowcent.cn/oauth/token \
  -u "abc123:your_client_secret" \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=authorization_code&code=SplxlOBeZQQYbYS6WxSbIA"

3.4 ユーザー情報へのアクセス(UserInfo)

エンドポイント:

GET https://open-api.ham.nowcent.cn/oauth/userinfo

リクエストヘッダー:

Authorization: Bearer {access_token}

注意:UserInfoエンドポイントはAccess Tokenとクライアント認証情報の両方が必要です(二要素検証)。

成功レスポンス(200 OK):

json
{
  "open_id": "3f7a9c2b...e8",
  "nickname": "太郎",
  "avatar_url": "https://cdn.ham.nowcent.cn/avatar/xxx.jpg",
  "is_student": true,
  "scope": "profile is_student"
}

フィールド説明:

フィールド説明返却条件
open_id現在のアプリにおけるユーザーの安定した一意識別子常に返却
nicknameユーザーニックネームprofileが付与された場合
avatar_urlユーザーアバターURLprofileが付与された場合
is_student学生かどうかis_studentが付与された場合
scope実際に付与されたスコープ(スペース区切り)常に返却

cURL例:

bash
curl https://open-api.ham.nowcent.cn/oauth/userinfo \
  -u "abc123:your_client_secret" \
  -H "Authorization: Bearer a1b2c3d4e5f6..."

3.5 トークンの種類と有効期間

トークン有効期間備考
authorization_code5分ワンタイム認証情報、交換後に無効化
access_token2時間(expires_in = 7200Opaqueトークン — クライアントで解析を試みない
Refresh Token提供なしAccess Token期限切れ後は再認可が必要

4. セキュリティプラクティスと注意事項

4.1 セキュリティベストプラクティス

  • すべてのHTTP呼び出しはHTTPSを使用、TLS 1.2+
  • client_secretaccess_tokenサーバーサイドのみで保存 — フロントエンドコード、モバイルバンドル、公開リポジトリには含めない
  • access_tokenをブラウザに送信する必要がある場合は、HttpOnly + Secure + SameSite=Lax/Strict Cookieを使用
  • CSRF防御のためstateパラメータを常に使用・検証
  • 「フロントエンドがDeep Linkを起動 → サーバーがTokenを交換 → サーバーがUserInfoを呼び出す」の分担を厳守
  • スコープ申請は最小権限の原則に従う
  • open_idを安定したユーザー識別子として使用

4.2 一般的なセキュリティリスク

リスク攻撃方法対策
CSRF攻撃者が認可リンクを作成し被害者を誘導ランダムなstateを強制し、コールバックで厳密に検証
コード傍受悪意のあるアプリがURL Schemeでコールバックを乗っ取り事前登録済みのHTTPS redirect_uriを使用
client_secret漏洩secretがフロントエンドバンドルや公開リポジトリに含まれるsecretはサーバーサイドのみ;鍵管理を使用;定期的にローテーション
トークン漏洩URL、Referrer、ログ経由で漏洩トークンはヘッダーのみ;ログをサニタイズ
XSSトークン窃取フロントエンドスクリプトがlocalStorageからトークンを読み取りHttpOnly Cookieを使用;厳格なCSP

4.3 エラー処理

HTTPステータスエラートリガークライアントアクション
400unsupported_grant_typegrant_typeauthorization_codeでないリクエストパラメータを確認
400invalid_request必須パラメータの欠落パラメータを修正して再試行
400invalid_grantcodeが無効/期限切れ/使用済みユーザーに再認可を案内
401invalid_clientクライアント認証情報エラークライアント認証情報を確認
401invalid_tokenaccess_tokenが無効/期限切れユーザーに再認可を案内
403insufficient_scopeトークンがこのclient_idに付与されていない正しい認証情報を使用するか再認可
5xxserver_errorサーバーエラー指数バックオフで再試行

参考仕様

  • RFC 6749 — The OAuth 2.0 Authorization Framework
  • RFC 6750 — The OAuth 2.0 Authorization Framework: Bearer Token Usage
  • RFC 9700 — Best Current Practice for OAuth 2.0 Security

オープンソース

HamのWebクライアントはGitHubでオープンソース公開されています:whu-ham/ham-web。OAuth 2.0認可の実装を参考にできます。