Supabaseを使ってみたい!
個人開発で、Supabaseを使用したログイン認証を行いたいと思い実装を進めていました。
その中で……
→ログイン処理はできたけど遷移後の画面でセッション情報が保持できていない……!!
となったので、対処法の備忘録を記載します。
SSRでのセッション保持
SupabaseのAPIですが、基本的にCookieを使用してセッション情報の保持を行っています。
クライアントの作成は、以下のようなコードで実装可能です。
import { createServerClient, parseCookieHeader, serializeCookieHeader } from '@supabase/ssr'
export function createSupabaseClient(request: Request) {
const headers = new Headers()
return createServerClient(process.env.SUPABASE_URL!, process.env.SUPABASE_SECRET_KEY!, {
cookies: {
getAll() {
return parseCookieHeader(request.headers.get('Cookie') ?? '')
},
setAll(cookiesToSet) {
cookiesToSet.forEach(({ name, value, options }) =>
headers.append('Set-Cookie', serializeCookieHeader(name, value, options))
)
},
},
});
}
ですが、React Router v7の環境だとログイン時に上記クライアントを使用するとセッションが保持できず、遷移後の画面でログインしたユーザ情報が取得できません。
海外の方がYouTubeで投稿していたのですが、createBrowserClientを使用する事でセッションの保持が可能のようでした。
それなら早速action内で定義して……
→なんかCookie周りでエラーが出るんだけど……!?
createBrowserClientの使用
createBrowserClientですが、React Router v7のaction内では使用できません。
(ブラウザ側の処理なので、サーバ側のactionで使用できないのは当たり前ですね……)
そのため、処理はレンダリングするexport function内に記載するようにしましょう。
// 既に記載済みの処理は省略します
import { createBrowserClient } from '@supabase/ssr'
export function createLoginClient(SUPABASE_URL: string | null, SUPABASE_ANON_KEY: string | null) {
return createBrowserClient(SUPABASE_URL!, SUPABASE_ANON_KEY!);
}
import { createLoginClient } from "./client";
export async function loader() {
return {
// env情報はレンダリング処理内では取得できないため、loaderから渡すようにしましょう
env: {
SUPABASE_URL: process.env.SUPABASE_URL!,
SUPABASE_ANON_KEY: process.env.SUPABASE_ANON_KEY!,
}
};
}
export default function Login({ loaderData }: Route.ComponentProps) {
const [error, setError] = useState<string | null>(null);
const { env } = loaderData;
const navigator = useNavigate();
const doLogin = async (event: React.FormEvent<HTMLFormElement>) => {
event.preventDefault();
const formData = new FormData(event.currentTarget);
const data = Object.fromEntries(formData.entries());
// createBrowserClientを読み込みます
const supabase = createLoginClient(env.SUPABASE_URL, env.SUPABASE_ANON_KEY);
// ログイン処理を実行します
const { error } = await supabase.auth.signInWithPassword({
email: data.email as string,
password: data.password as string,
});
if (!error) {
// エラーがなければホーム画面に遷移します
navigator("/home");
} else {
// ログインに失敗した場合はエラ〜メッセージを表示します
setError(error.message);
return;
}
}
return (
<div className="flex h-full flex-col items-center justify-center gap-y-5">
<div className="p-6">
<Form method="POST" onSubmit={doLogin}>
<div>
<label>
メールアドレス
</label>
<input name="email" type="email" />
</div>
<div>
<label>
パスワード
</label>
<input name="password" type="password" />
</div>
<button type="submit" value="ログイン">
ログイン
</button>
<Link to="/forgot_password">
パスワードをお忘れですか?
</Link>
<Link to="/register">
新規ユーザー登録
</Link>
{error ? (
<p className="text-red-500">{error}</p>
) : null}
</Form>
</div>
</div>
);
}
ここまで来ればログイン→ホーム画面に遷移した際にセッション情報が保持され、ホーム画面でユーザ情報が取得できるようになります。
番外編:APIキーのエラー
2025/10/26現在、こちらの処理はレガシーAPIキーのみ使用可能です。
(ここで更につまづきました)
レガシーAPIキーを無効にしている方は、再有効化して使用するようにしましょう。
おわりに
ログイン認証周りの記載がネット上で意外とヒットしなかったため、今後Supabaseを実装する方の参考になればと思います。
React RouterやTypeScriptはまだまだ初学者なので、もっと効率のいい実装方法などありましたらコメントしていただけると嬉しいです!