SPAでのSSO認証フローを実装する
概要
このチュートリアルでは、KurocoをバックエンドAPIとして利用するフロントエンドSPA(Single Page Application)において、SSOログインフローの全体を実装する方法を解説します。
SSOによるログインをフロントエンドで利用するではKurocoの基本設定とgrant_tokenの概念を説明していますが、本チュートリアルではフロントエンド側の実装の詳細に焦点を当てます。具体的には、リダイレクトフローの処理、トークンの交換、ログイン後にユーザーの元のページへ復帰する方法について説明します。
以下のシーケンス図は、Microsoft Entra IDをIdPとして使用した場合の完全なフローを示しています。Kurocoで設定されたSSOプロバイダー(OAuth SP、SAML SP、IDaaS SP)であれば、同じパターンが適用されます。

学べること
- SSOリダイレクトフローのエンドツーエンドの仕組み
- SSOリダイレクトをまたいでユーザーの元のURLを保存・復元する方法
grant_tokenをaccess_tokenに交換する方法- ログインを確定し、元のページに遷移する方法
前提条件
-
SSOが設定済みのKurocoプロジェクト(OAuth SP、SAML SP、またはIDaaS SP)
- SSO設定画面の 「(API用) Grantトークン生成」 で対象APIにチェックを入れてください
-
動的アクセストークンセキュリティのAPIに、以下の
tokenエンドポイントを作成済みであること項目 設定内容 パス token カテゴリー 認証 モデル Login(v1) オペレーション token use_refresh_token チェックあり access_token_lifespan 86400(1日、秒単位) refresh_token_lifespan 604800(7日、秒単位) -
フロントエンドSPA(React、Vue、Nuxt、Next.jsなど)
まだKurocoでSSOを設定していない場合は、以下のチュートリアルを先にご参照ください:
フロー概要
SSOログインフローは以下のステップで構成されます:
- 未認証でユーザーが保護されたページにアクセス
- フロントエンドが現在のURLを保存し、KurocoのSSOログインエンドポイントにリダイレクト
- Kurocoがブラウザを外部IdP(例:Entra ID)にリダイレクト
- ユーザーがIdPで認証
- IdPが結果をKurocoに返却し、KurocoがフロントエンドのコールバックURLに
grant_token付きでリダイレクト - フロントエンドが
grant_tokenをaccess_tokenとrefresh_tokenに交換 - フロントエンドがprofileエンドポイントを呼び出してログインを確定
- フロントエンドがユーザーを元のページに遷移
トークンの種類と役割
SSOフローでは3種類のトークンが登場します。それぞれ用途と寿命が異なります。
| トークン | 用途 | 取得方法 | 寿命 | 使用回数 |
|---|---|---|---|---|
grant_token | access_tokenを発行するための一時トークン | SSO認証成功後、リターンURLのクエリパラメータとして付与される | 非常に短い(即時交換が必要) | 1回のみ |
access_token | APIリクエストの認証に使用。X-RCMS-API-ACCESS-TOKENヘッダーに設定する | grant_tokenまたはrefresh_tokenをtokenエンドポイントに送信して取得 | 設定値(例:86400秒 = 1日) | 有効期限内は何度でも使用可能 |
refresh_token | 期限切れのaccess_tokenを再発行するためのトークン | grant_tokenをtokenエンドポイントに送信した際にaccess_tokenと同時に取得 | 設定値(例:604800秒 = 7日) | 有効期限内は何度でも使用可能 |
トークンの流れ:
SSO認証成功
└→ grant_token(URLパラメータ)
└→ tokenエンドポイントに送信
├→ access_token(API認証に使用)
└→ refresh_token(access_token期限切れ時に再発行)
└→ tokenエンドポイントに送信
├→ 新しいaccess_token
└→ 新しいrefresh_token
access_tokenとrefresh_tokenはいずれもtokenエンドポイント(/rcms-api/{api_id}/token)から取得しますが、リクエストボディのパラメータが異なります:
- 初回発行:
{ "grant_token": "..." } - 再発行(リフレッシュ):
{ "refresh_token": "..." }
使用するエンドポイント
本チュートリアルで使用するエンドポイントの一覧です。いずれもKuroco管理画面であらかじめ作成しておく必要があります。
| エンドポイント | メソッド | パス | 用途 | 認証ヘッダー |
|---|---|---|---|---|
| SSOログイン | GET | 管理画面のSSO設定から取得 | SSO認証フローを開始する | 不要 |
| token | POST | /rcms-api/{api_id}/token | grant_token→access_tokenの交換、refresh_tokenによる再発行 | 不要 |
| profile | GET | /rcms-api/{api_id}/profile | ログイン確認とユーザー情報の取得 | X-RCMS-API-ACCESS-TOKEN |
| logout | POST | /rcms-api/{api_id}/logout | ログアウト処理 | X-RCMS-API-ACCESS-TOKEN |
tokenエンドポイントとprofileエンドポイントは、Kuroco管理画面のAPI設定で以下のように作成します:
tokenエンドポイント(前提条件の設定テーブルを参照)
- カテゴリー:認証 / モデル:Login(v1) / オペレーション:token
profileエンドポイント
- カテゴリー:認証 / モデル:Login(v1) / オペレーション:profile
logoutエンドポイント
- カテゴリー:認証 / モデル:Login(v1) / オペレーション:logout
実装
ステップ1:未認証状態の検出
ユーザーが保護されたページにアクセスした際、有効なトークンがあるかを確認します。なければ、ログイン後にリダイレクトできるよう現在のURLを保存します。
const currentPath = window.location.pathname + window.location.search
if (!accessToken) {
sessionStorage.setItem("post_login_redirect", currentPath)
}
リダイレクトURLの保存にはlocalStorageではなくsessionStorageを使用してください。ブラウザタブを閉じたときに自動的にクリアされるため、一時的なログイン状態の管理により適しています。
ステップ2:SSOログインへのリダイレクト
ユーザーをKurocoのSSOログインURLにリダイレクトします。このURLはKuroco管理画面のSSO設定画面から取得できます。
SSOの種類によって、ログインURLの確認場所が異なります:
| SSO種別 | 管理画面の場所 | URL表示項目 |
|---|---|---|
| OAuth SP | [外部システム連携] → [OAuth SP] → 編集画面 | ログインURL |
| SAML SP | [外部システム連携] → [SAML SP] → 編集画面 | ログインSAML SP ACS URI |
| IDaaS SP | [外部システム連携] → [IDaaS SP] → 編集画面 | ログインURL |
// KurocoのAPIドメイン(独自ドメインを設定している場合はそのドメインを使用)
const KUROCO_API = "https://api.example.com"
// SSOログインURLはKuroco管理画面のSSO設定画面から取得します
// 例: https://{管理画面ドメイン}/direct/login/saml_login/?spid={sp_id}
const SSO_LOGIN_URL = "https://{management-domain}/direct/login/saml_login/?spid={sp_id}"
SSOログインURLへリダイレクトします。api_idパラメータを付与すると、grant_tokenを生成する対象APIを明示的に指定できます(管理画面で複数APIにチェックを入れている場合に有用です)。
// api_idを指定する場合はクエリパラメータに追加
window.location.href = `${SSO_LOGIN_URL}&api_id={api_id}`
// api_idが不要な場合(対象APIが1つのみの場合)
window.location.href = SSO_LOGIN_URL
SSOログインURLはKuroco管理画面のSSO設定画面から取得してください。コールバックURL(認証後のリダイレクト先)は管理画面の 「リターンURL(成功)」 で設定します。ユーザーの実際の戻り先は、ステップ1で示したようにsessionStorageで別途管理します。
ステップ3:コールバックの処理
SSO認証が成功すると、Kurocoは管理画面で設定した「リターンURL(成功)」に grant_token と member_id をGETパラメータとして付与してリダイレクトします(例:https://front-end.example.com/?grant_token=*********&member_id=123)。コールバックページでこれらを取得します。
const params = new URLSearchParams(window.location.search)
const grantToken = params.get("grant_token")
const memberId = params.get("member_id")
if (!grantToken) {
// エラー処理:ログインページにリダイレクトするか、エラーを表示
throw new Error("コールバックURLにgrant_tokenが存在しません")
}
ステップ4:grant_tokenをaccess_tokenに交換
grant_tokenをKurocoのトークンエンドポイントに送信して、access_tokenとrefresh_tokenを取得します。
const response = await fetch(
`${KUROCO_API}/rcms-api/{api_id}/token`,
{
method: "POST",
credentials: "include",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({ grant_token: grantToken }),
}
)
const data = await response.json()
const { access_token, refresh_token } = data
grant_tokenは1回限り有効な短命のトークンです。URLに露出するため、コールバック受信後直ちにアクセストークンに交換する必要があり、再利用はできません。
トークンエンドポイントのレスポンスは以下のような構造です。実際のトークン文字列は .value プロパティに格納されています:
{
"access_token": { "value": "アクセストークン文字列", ... },
"refresh_token": { "value": "リフレッシュトークン文字列", ... }
}
ステップ5:トークンの保存
トークンを安全に保存します。SPAではメモリ内での保存が推奨されます。トークン文字列は .value から取得します。
// メモリまたはセキュアなストレージに保存
setAccessToken(access_token.value)
setRefreshToken(refresh_token.value)
ステップ6:ログインの確定
新しいアクセストークンでprofileエンドポイントを呼び出し、ログインを確認します。
const profileResponse = await fetch(`${KUROCO_API}/rcms-api/{api_id}/profile`, {
credentials: "include",
headers: {
"X-RCMS-API-ACCESS-TOKEN": access_token.value,
},
})
const user = await profileResponse.json()
ステップ7:元のページへの遷移
sessionStorageから保存済みのURLを取得し、ユーザーを元のページに遷移させます。
const redirectPath =
sessionStorage.getItem("post_login_redirect") || "/"
sessionStorage.removeItem("post_login_redirect")
// ルーターのナビゲーションを使用(例:React Router、Vue Router)
navigate(redirectPath)
トークンリフレッシュ
access_tokenの有効期限が切れた場合は、refresh_tokenを使用して新しいトークンを取得します。リフレッシュも失敗した場合は、SSOフローを再実行します。
const refreshResponse = await fetch(
`${KUROCO_API}/rcms-api/{api_id}/token`,
{
method: "POST",
credentials: "include",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({ refresh_token: refreshToken }),
}
)
if (!refreshResponse.ok) {
// リフレッシュ失敗 — SSOフローを再開
sessionStorage.setItem(
"post_login_redirect",
window.location.pathname + window.location.search
)
window.location.href = SSO_LOGIN_URL
return
}
const refreshData = await refreshResponse.json()
setAccessToken(refreshData.access_token.value)
setRefreshToken(refreshData.refresh_token.value)
APIリクエストが401 Unauthorizedを返した場合に、自動的にrefresh_tokenでトークンを再取得してリクエストをリトライする仕組みを実装すると、ユーザー体験が向上します。リトライも失敗した場合はトークンを破棄してSSOフローを再開します。
重要な設計ポイント
SSOログインURLとコールバックURL
SSOログインURL(例:https://{管理画面ドメイン}/direct/login/saml_login/?spid={sp_id})と、認証後のコールバックURL(リターンURL)は、いずれもKuroco管理画面のSSO設定で管理します。SSO設定画面の 「(API用) Grantトークン生成」 で対象APIにチェックを入れることで、リターンURL遷移時にgrant_tokenパラメータが付与されるようになります。ユーザーの実際の戻り先は、フロントエンド側でsessionStorageを使用して別途管理します。
認証スコープごとに1つのAPI
Kurocoでは、動的アクセストークン認証の場合、ログインセッションはAPI(api_id)単位でスコープされます。SSOログインを使用した場合、ユーザーはSSOが設定されたAPIに対してのみ認証されます。認証が必要なすべてのエンドポイントを同一のapi_idにまとめることで、セッションの問題を回避できます。
注意: Cookie認証の場合は、複数の
api_id間で認証状態が共有されます。詳細はAPIのセキュリティを参照してください。
grant_tokenのセキュリティ
grant_tokenはURLに露出するため、コールバックで受け取ったら直ちにaccess_tokenに交換してください。詳細は上記のトークンの種類と役割を参照してください。
関連ドキュメント
サポート
お探しのページは見つかりましたか?解決しない場合は、問い合わせフォームからお問い合わせいただくか、Slackコミュニティにご参加ください。