安全な認証パターン
トークン保存(memoryとlocalStorageとhttpOnly cookie)、サイレントリフレッシュ、タブを閉じたときのログアウト
「安全な認証パターン」はCoddyKit上の無料Vue Academyレッスンです。 これはレッスン4/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはVue Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 Vue Academyコースには全4レッスンが含まれています。
トークンと保存場所
SPAはトークンで認証しますが、どこに保存するかによってXSSやCSRFへの露出が決まります。現在一般的な方法では、短期間有効なアクセストークンと長期間有効なリフレッシュトークンを分け、それぞれ別の方法で保存します。
localStorageの問題
トークンをlocalStorageに保存するのは便利ですが危険です。XSSで注入されたスクリプトはそれを読み取り、トークンを外部へ持ち出せます。認証情報をそこに保存するのは避けてください。
// AVOID
localStorage.setItem("token", accessToken);メモリ内のアクセストークン
アクセストークンはJavaScript変数またはリアクティブなrefに保持します。リロードすると消えるため、XSSが成功しても攻撃できる時間が大幅に短くなり、ディスク上に何も残りません。
import { ref } from "vue";
export const accessToken = ref(null);httpOnly Cookieのリフレッシュトークン
リフレッシュトークンはHttpOnly、Secure、SameSite属性を持つCookieに保存します。JavaScriptから読み取れないためXSSで盗まれることがなく、ブラウザーも認証エンドポイントにのみ送信します。
Set-Cookie: refresh=...; HttpOnly; Secure; SameSite=Strict; Path=/authアクセストークンを付加する
Axiosのリクエストインターセプターで、メモリ内のアクセストークンをすべての呼び出しのAuthorizationヘッダーに追加します。
api.interceptors.request.use((config) => {
if (accessToken.value) {
config.headers.Authorization = "Bearer " + accessToken.value;
}
return config;
});有効期限を検出する:401
アクセストークンの有効期限が切れると、サーバーは401 Unauthorizedを返します。レスポンスインターセプターでこれを検出し、更新を開始します。
api.interceptors.response.use(
(res) => res,
async (error) => {
if (error.response?.status === 401) {
// attempt refresh
}
return Promise.reject(error);
}
);トークンを更新する
401を受け取ったら、リフレッシュエンドポイントを呼び出します。ブラウザーはhttpOnlyリフレッシュCookieを自動的に送信し(withCredentials)、サーバーは新しいアクセストークンを返します。
const { data } = await axios.post("/auth/refresh", null, {
withCredentials: true
});
accessToken.value = data.accessToken;元のリクエストを再試行する
リフレッシュ後、新しいトークンで失敗した元のリクエストを再実行し、ユーザーにそれを意識させないようにします。
async (error) => {
const original = error.config;
if (error.response?.status === 401 && !original._retry) {
original._retry = true;
const { data } = await axios.post("/auth/refresh", null, { withCredentials: true });
accessToken.value = data.accessToken;
original.headers.Authorization = "Bearer " + data.accessToken;
return api(original);
}
return Promise.reject(error);
}リフレッシュの集中を防ぐ
多くのリクエストが同時に 401 を返した場合は、1つの実行中のリフレッシュ処理の後ろにキューイングし、リフレッシュエンドポイントを繰り返し呼び出さないようにします。
let refreshing = null;
function refresh() {
if (!refreshing) {
refreshing = axios.post("/auth/refresh", null, { withCredentials: true })
.finally(() => { refreshing = null; });
}
return refreshing;
}ログアウトする
ログアウト時には、メモリ上のトークンを消去し、サーバー側でリフレッシュCookieを消去するエンドポイントを呼び出します。
async function logout() {
accessToken.value = null;
await axios.post("/auth/logout", null, { withCredentials: true });
}CSRF対策と組み合わせる
リフレッシュCookieは自動的に送信されるため、他のCookie認証ルートと同様に、SameSite とCSRFトークンでこのエンドポイントを保護します。
理解度チェック
アクセストークンとリフレッシュトークンは、それぞれどこに保存すべきでしょうか。
まとめ
アクセストークンはメモリ上のrefに保存し(localStorageには絶対に保存しません)、リフレッシュトークンは HttpOnly Cookieに保存します。リクエストインターセプターがベアラートークンを付加し、レスポンスインターセプターが 401 を検出すると、リフレッシュエンドポイントを呼び出してトークンを更新し、元のリクエストを再試行します。さらに、同時に発生したリフレッシュ処理を重複排除し、CSRF対策と組み合わせます。
よくある質問
「安全な認証パターン」レッスンは無料ですか?
はい。「安全な認証パターン」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、Vue Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 Vue Academyコースには全4レッスンが含まれています。
「安全な認証パターン」で何を学びますか?
トークン保存(memoryとlocalStorageとhttpOnly cookie)、サイレントリフレッシュ、タブを閉じたときのログアウト ブラウザで直接実行するハンズオンコードでVue Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。
Vue Academyを始めるのに経験は必要ですか?
事前経験は必要ありません。CoddyKitのVue Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン4/4です。
「安全な認証パターン」レッスンにはどのくらい時間がかかりますか?
ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。
このVue Academyレッスンでコードを書いて実行できますか?
はい。すべてのVue Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。