メインコンテンツまでスキップ

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リダイレクトフローのエンドツーエンドの仕組み
  • SSOリダイレクトをまたいでユーザーの元のURLを保存・復元する方法
  • grant_tokenaccess_tokenに交換する方法
  • ログインを確定し、元のページに遷移する方法

前提条件

  • SSOが設定済みのKurocoプロジェクト(OAuth SP、SAML SP、またはIDaaS SP)
  • 動的アクセストークンセキュリティとtokenエンドポイントを持つAPI
  • フロントエンドSPA(React、Vue、Nuxt、Next.jsなど)

まだKurocoでSSOを設定していない場合は、以下のチュートリアルを先にご参照ください:

フロー概要

SSOログインフローは以下のステップで構成されます:

  1. 未認証でユーザーが保護されたページにアクセス
  2. フロントエンドが現在のURLを保存し、KurocoのSSOログインエンドポイントにリダイレクト
  3. Kurocoがブラウザを外部IdP(例:Entra ID)にリダイレクト
  4. ユーザーがIdPで認証
  5. IdPが結果をKurocoに返却し、KurocoがフロントエンドのコールバックURLにgrant_token付きでリダイレクト
  6. フロントエンドがgrant_tokenaccess_tokenrefresh_tokenに交換
  7. フロントエンドがprofileエンドポイントを呼び出してログインを確定
  8. フロントエンドがユーザーを元のページに遷移

実装

ステップ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ログインエンドポイントにリダイレクトします。redirect_uriパラメータは、認証後にKurocoがユーザーを戻すコールバックURLを指定します。

const KUROCO_API = "https://api.example.com"
const CALLBACK_URL = "https://front-end.example.com/auth/callback"

const redirectUri = encodeURIComponent(CALLBACK_URL)
window.location.href = `${KUROCO_API}/sso/login?redirect_uri=${redirectUri}`
注意

redirect_uriは固定の事前登録済みURLでなければなりません。動的に変更しないでください。これはセキュリティ上の要件です。ユーザーの実際の戻り先は、ステップ1で示したようにsessionStorageで別途管理します。

ステップ3:コールバックの処理

コールバックページ(例:/auth/callback)を作成し、URLクエリパラメータからgrant_tokenを取得します。

const params = new URLSearchParams(window.location.search)
const grantToken = params.get("grant_token")

if (!grantToken) {
// エラー処理:ログインページにリダイレクトするか、エラーを表示
throw new Error("コールバックURLにgrant_tokenが存在しません")
}

ステップ4:grant_tokenをaccess_tokenに交換

grant_tokenをKurocoのトークンエンドポイントに送信して、access_tokenrefresh_tokenを取得します。

const response = await fetch(
`${KUROCO_API}/rcms-api/{api_id}/token`,
{
method: "POST",
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に露出するため、コールバック受信後直ちにアクセストークンに交換する必要があり、再利用はできません。

ステップ5:トークンの保存

トークンを安全に保存します。SPAではメモリ内での保存が推奨されます。

// メモリまたはセキュアなストレージに保存
setAccessToken(access_token)
setRefreshToken(refresh_token)

ステップ6:ログインの確定

新しいアクセストークンでprofileエンドポイントを呼び出し、ログインを確認します。

const profileResponse = await fetch(`${KUROCO_API}/profile`, {
headers: {
Authorization: `Bearer ${access_token}`,
},
})

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",
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 = `${KUROCO_API}/sso/login?redirect_uri=${encodeURIComponent(CALLBACK_URL)}`
return
}

const refreshData = await refreshResponse.json()
setAccessToken(refreshData.access_token)

重要な設計ポイント

redirect_uriは固定

SSOログインエンドポイントに渡すredirect_uriは、常に同じ固定のコールバックURL(例:https://front-end.example.com/auth/callback)でなければなりません。ユーザーの実際の戻り先は、フロントエンド側でsessionStorageを使用して別途管理します。

認証スコープごとに1つのAPI

Kurocoでは、ログインセッションはAPI単位でスコープされます。SSOログインを使用した場合、ユーザーはSSOが設定されたAPIに対してのみ認証されます。認証が必要なすべてのエンドポイントを1つのAPIにまとめることで、セッションの問題を回避できます。

grant_tokenのセキュリティ

grant_tokenは以下の特性を持ちます:

  • URLに露出する(クエリパラメータとして)
  • 1回のみ有効
  • 短命(すぐに期限切れ)

コールバックで受け取ったら、直ちにアクセストークンに交換してください。

関連ドキュメント


サポート

お探しのページは見つかりましたか?解決しない場合は、問い合わせフォームからお問い合わせいただくか、Slackコミュニティにご参加ください。