はじめに
「4S でログイン」は、OAuth 2.0 / OpenID Connect (OIDC) 準拠の認証機能です。外部アプリケーションは 4S アカウントを使ったログインと、ユーザーに代わって 4S の読み取り(GET)API を利用できます。
標準準拠のため、NextAuth (Auth.js)、openid-client など一般的な OIDC ライブラリがそのまま利用できます。対応フローは Authorization Code + PKCE (S256) のみです。
アプリの登録は 4S の開発者メニュー(https://4s.link/developer)から行います。登録すると client_id と client_secret が発行されます。client_secret は登録直後に一度だけ表示されるため、安全な場所に保管してください。
基本情報
| 項目 | 値 |
|---|---|
| Issuer | https://api.4s.link |
| 対応フロー | Authorization Code + PKCE (S256) |
| クライアント認証 | client_secret_basic / client_secret_post / none (public + PKCE) |
| ID Token 署名 | RS256 |
| アクセストークン有効期限 | 1 時間 |
| リフレッシュトークン有効期限 | 60 日(ローテーション方式) |
# OIDC Discoveryhttps://api.4s.link/.well-known/openid-configuration# JWKS (公開鍵)https://api.4s.link/.well-known/jwks.json# 認可エンドポイントhttps://4s.link/oauth/authorize# トークンエンドポイントhttps://api.4s.link/oauth/token# UserInfohttps://api.4s.link/oauth/userinfo# トークン失効https://api.4s.link/oauth/revoke
認証フロー
Authorization Code + PKCE フローの流れは次のとおりです。(1) アプリが code_verifier を生成し、その S256 ハッシュ(code_challenge)を付けて認可エンドポイントへユーザーをリダイレクトする。(2) ユーザーが 4S にログインして同意すると、redirect_uri に認可コード(code)が返る。(3) アプリはトークンエンドポイントで code + code_verifier をトークンに交換する。
https://4s.link/oauth/authorize認可エンドポイントはブラウザでユーザーをリダイレクトさせる URL です(API ではありません)。以下のクエリパラメータを付与してください。
クエリパラメータ
response_typestring必須code 固定
client_idstring必須開発者メニューで発行されたクライアント ID
redirect_uristring必須登録済みのリダイレクト URI と完全一致すること
statestringCSRF 対策のランダム値。コールバックでそのまま返される(強く推奨)
noncestringID Token の nonce クレームとして返されるランダム値(推奨)
code_challengestring必須code_verifier の SHA-256 を base64url エンコードした値
code_challenge_methodstring必須S256 固定
promptstringconsent を指定すると同意済みでも同意画面を再表示する。none はサポートされず interaction_required が返る
ユーザーが承認すると redirect_uri に ?code=...&state=... が付与されて戻ります。拒否した場合や検証エラーの場合は ?error=access_denied などが返ります。認可コードの有効期限は 5 分間・1 回限りです。
const crypto = require("crypto");const codeVerifier = crypto.randomBytes(32).toString("base64url");const codeChallenge = crypto.createHash("sha256").update(codeVerifier).digest("base64url");console.log({ codeVerifier, codeChallenge });
Discovery / JWKS
/.well-known/openid-configurationOIDC Discovery ドキュメントです。エンドポイント URL・署名アルゴリズムなどのメタデータを返します。OIDC ライブラリには issuer としてこのオリジンを設定すれば、残りは自動で解決されます。
/.well-known/jwks.jsonID Token の署名を検証するための公開鍵(JWK Set)です。ID Token のヘッダの kid と一致する鍵で RS256 署名を検証してください。鍵はローテーションされることがあるため、JWKS は都度取得するかキャッシュの失効を実装してください(Cache-Control: max-age=300)。
curl https://api.4s.link/.well-known/openid-configuration
トークンエンドポイント
/oauth/token認可コードをトークンに交換する、またはリフレッシュトークンでトークンを更新するエンドポイントです。リクエストボディは application/x-www-form-urlencoded で送信してください。confidential クライアントは client_secret_basic(Authorization: Basic)または client_secret_post(ボディ)で認証します。
grant_type=authorization_code のパラメータ
grant_typestring必須authorization_code
codestring必須コールバックで受け取った認可コード
redirect_uristring必須認可リクエスト時と同じ値
code_verifierstring必須code_challenge の元になった PKCE 検証値
grant_type=refresh_token のパラメータ
grant_typestring必須refresh_token
refresh_tokenstring必須有効なリフレッシュトークン
リフレッシュトークンはローテーション方式です。refresh_token グラントを実行するたびに新しいリフレッシュトークンが発行され、古いトークンは無効になります。失効済みリフレッシュトークンの再利用を検知した場合、安全のためそのユーザー×クライアントのすべてのトークンが失効します。必ず最新のリフレッシュトークンを保存してください。
curl -X POST https://api.4s.link/oauth/token \-u "YOUR_CLIENT_ID:YOUR_CLIENT_SECRET" \-H "Content-Type: application/x-www-form-urlencoded" \-d "grant_type=authorization_code" \-d "code=AUTHORIZATION_CODE" \-d "redirect_uri=https://example.com/callback" \-d "code_verifier=CODE_VERIFIER"
ID Token
トークンレスポンスには常に ID Token(RS256 署名の JWT)が含まれます。検証時は (1) JWKS の kid 一致鍵で署名を検証、(2) iss が issuer と一致、(3) aud が自分の client_id と一致、(4) exp が未来、(5) 認可リクエストで nonce を送った場合は nonce クレームの一致、を確認してください。OIDC ライブラリを使えばこれらは自動で行われます。
主なクレーム
| クレーム | 説明 |
|---|---|
sub | ユーザーの一意 ID(4S のユーザー ID) |
iss | 発行者(issuer) |
aud | クライアント ID |
auth_time | ユーザーが認可した時刻(Unix 秒) |
nonce | 認可リクエストの nonce(送信した場合のみ) |
name / given_name / family_name / picture / profile / preferred_username / locale | プロフィール情報(常に含まれる) |
email / email_verified | メールアドレス(常に含まれる) |
{"sub": "a1b2c3d4-....","iss": "https://api.4s.link","aud": "YOUR_CLIENT_ID","iat": 1783900000,"exp": 1783903600,"auth_time": 1783899990,"nonce": "RANDOM_NONCE","name": "太郎 山田","given_name": "太郎","family_name": "山田","picture": "https://.../avatar.png","profile": "https://4s.link/taro","preferred_username": "taro","locale": "ja","email": "taro@example.com","email_verified": true}
トークン失効
/oauth/revokeRFC 7009 準拠のトークン失効エンドポイントです。ユーザーがアプリからログアウトした際などに、不要になったトークンを失効させてください。リフレッシュトークンを失効させると、そこから発行されたアクセストークンも同時に失効します。RFC 7009 の仕様どおり、不明なトークンを指定しても 200 が返ります。
ボディパラメータ
tokenstring必須失効させるアクセストークンまたはリフレッシュトークン
curl -X POST https://api.4s.link/oauth/revoke \-u "YOUR_CLIENT_ID:YOUR_CLIENT_SECRET" \-H "Content-Type: application/x-www-form-urlencoded" \-d "token=4s_rt_..."
API を呼び出す
取得したアクセストークンを Authorization: Bearer ヘッダに付けて、4S の API を呼び出します。OAuth アクセストークンで利用できるのは、以下の各カテゴリに記載された読み取り(GET)エンドポイントに限られます。
共通仕様
| 項目 | 内容 |
|---|---|
| ベース URL | https://api.4s.link |
| 認証 | Authorization: Bearer <access_token> |
| 利用可能な範囲 | 各カテゴリに記載された GET エンドポイントのみ |
| ページネーション | 一覧系は page / perPage クエリ。レスポンスに pageInfo(totalCount / totalPages / page / perPage) |
| エラー(401) | トークンが無効・失効・期限切れ |
| エラー(403) | 許可された GET エンドポイント以外へのアクセス |
各カテゴリの代表的なエンドポイントを以下に示します。リクエスト/レスポンスの詳細な項目は OpenAPI 仕様(openapi.yaml)を参照してください。
curl https://api.4s.link/users/me \-H "Authorization: Bearer 4s_at_..."
エラーリファレンス
トークンエンドポイント・UserInfo・イベント API は RFC 6749 / RFC 6750 形式のエラー({ error, error_description })を返します。認可エンドポイントのエラーは redirect_uri へのクエリパラメータで返ります(redirect_uri 自体が不正な場合を除く)。
| エラー | 発生箇所 | 説明 |
|---|---|---|
invalid_client | token / revoke | クライアント認証の失敗、またはアプリがサスペンド中 |
invalid_grant | token | 認可コード / リフレッシュトークンが無効・期限切れ・使用済み、PKCE 検証失敗、redirect_uri 不一致、連携解除済み |
invalid_request | token / authorize | 必須パラメータの不足・不正 |
access_denied | authorize | ユーザーが認可を拒否した |
interaction_required | authorize | prompt=none が指定されたが対話が必要(サイレント認証は非対応) |
unsupported_grant_type | token | authorization_code / refresh_token 以外の grant_type |
401 Unauthorized | リソース API | アクセストークンが無効・失効・期限切れ、またはアプリがサスペンド中 |
403 Forbidden | リソース API | 許可された GET エンドポイント以外へのアクセス(各カテゴリに記載のエンドポイントのみ利用可) |
{"error": "invalid_grant","error_description": "PKCE verification failed"}
連携例
汎用 OIDC ライブラリでは issuer を設定するだけで Discovery から各エンドポイントが自動解決されます。NextAuth (Auth.js) v5 の設定例を右に示します。redirect_uri(例: https://your-app.com/api/auth/callback/4s)を開発者メニューで忘れずに登録してください。
既知の制限: prompt=none(サイレント認証)と Dynamic Client Registration には対応していません。ID Token に at_hash クレームは含まれません。
import NextAuth from "next-auth";export const { handlers, auth, signIn, signOut } = NextAuth({providers: [{id: "4s",name: "4S",type: "oidc",issuer: "https://api.4s.link",clientId: process.env.FOURS_CLIENT_ID,clientSecret: process.env.FOURS_CLIENT_SECRET,authorization: {params: { scope: "openid profile email" },},// PKCE と state は NextAuth がデフォルトで有効化します},],});
デモアプリ
Next.js + TypeScript で実装した「4S でログイン」の動作サンプルです。ログインフロー(Authorization Code + PKCE)とプロフィール取得の実装を確認できます。
ユーザー / プロフィール
- GET
/usersユーザー一覧・検索ユーザーを検索・一覧取得します。search はスペース区切りで AND 検索され、slug・氏名・タイトル・自己紹介が対象です。 - GET
/users/me自分のプロフィール認証中ユーザー自身のプロフィールを取得します。email など非公開フィールドを含みます。 - GET
/users/:idユーザー詳細指定ユーザーの公開プロフィールを取得します(email は含みません)。 - GET
/users/:id/events参加イベント指定ユーザーが参加した(参加確定・チェックイン済み)イベントを開催日の降順で取得します。非公開イベントは除外されます。 - GET
/users/:id/communities参加コミュニティ指定ユーザーが参加している(承認済み・非公開以外の)コミュニティを取得します。ページングはありません。 - GET
/events/:eventId/entries自分の参加登録状態認証中ユーザーの、指定イベントに対する参加登録(キャンセル以外)を取得します。
組織
コミュニティ
イベント
- GET
/eventsイベント一覧・検索イベントを多彩なフィルタで検索・一覧取得します。公開レスポンスでは startTime / endTime / onlineUrl は含まれず、開催日時は schedules を参照します。groupByDate=true で開催日単位のグループ形状になります。 - GET
/events/my-entries自分の参加イベント認証中ユーザーが参加登録したイベントを、参加登録日時の降順で取得します。 - GET
/events/:idイベント詳細イベントの詳細を取得します。パスには ID または slug を指定できます。セッション・登壇者・ステージ・チケット・主催者などを含みます。 - GET
/events/:eventId/participants参加者一覧イベントの参加者(参加確定・チェックイン済みかつミーティング受付中)を取得します。参加者リストの公開設定に従いアクセス制御されます。 - GET
/events/:eventId/referral-rankingリファラル影響力ランキングイベントの招待チェーンに基づく影響力ランキング(上位 100 件)を取得します。 - GET
/events/:eventId/entries/:entryId/referral-ancestorsリファラル祖先(招待元チェーン)指定参加登録から招待元を上方向に辿り、対象に近い順で返します。呼び出しユーザーが当該イベントの確定参加者(CONFIRMED / CHECKED_IN)でない場合は 403 です。 - GET
/events/:eventId/entries/:entryId/referral-descendantsリファラル子孫(招待ツリー)指定参加登録を根として招待ツリーを下方向に展開します。各ノードの直接の子は childrenLimit + cursor でページングされ、子の総数(CONFIRMED / CHECKED_IN のみ)も返します。呼び出しユーザーが確定参加者でない場合は 403 です。