Closed26

SvelteKit で @auth/sveltekit を使って Google ログインできるようにする

薄田達哉 / tatsuyasusukida薄田達哉 / tatsuyasusukida

フックの作成

src/hooks.server.ts
import { SvelteKitAuth } from "@auth/sveltekit";
import Google from "@auth/core/providers/google";
import { GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET } from "$env/static/private";

export const handle = SvelteKitAuth({
    providers: [Google({
        clientId: GOOGLE_CLIENT_ID,
        clientSecret: GOOGLE_CLIENT_SECRET,
    })]
})
薄田達哉 / tatsuyasusukida薄田達哉 / tatsuyasusukida

ログイン/ログアウトページの作成

src/routes/+page.svelte
<script>
    import { signIn, signOut } from "@auth/sveltekit/client";
	import { page } from '$app/stores';
</script>

<h1>SvelteKit Auth Example</h1>
<p>
	{#if $page.data.session}
		{#if $page.data.session.user?.image}
			<span style="background-image: url('{$page.data.session.user.image}')" class="avatar"></span>
		{/if}
        <span class="signedInText">
            <small>Signed in as</small><br>
            <strong>{$page.data.session.user?.name ?? "User"}</strong>
        </span>
        <button on:click={() => signOut()} class="button">Sign out</button>
    {:else}
        <span class="notSignedIntText">You are not signed in</span>
        <button on:click={() => signIn("google")}>Sign in with Google</button>
	{/if}
</p>
薄田達哉 / tatsuyasusukida薄田達哉 / tatsuyasusukida

シークレットの生成

コマンド
openssl rand -hex 32
.env.local(追記)
AUTH_SECRET="0000000000000000000000000000000000000000000000000000000000000000"
薄田達哉 / tatsuyasusukida薄田達哉 / tatsuyasusukida

シークレットの設定

src/hooks.server.ts
import { SvelteKitAuth } from '@auth/sveltekit';
import Google from '@auth/core/providers/google';
import { AUTH_SECRET, GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET } from '$env/static/private';

export const handle = SvelteKitAuth({
	providers: [
		Google({
			clientId: GOOGLE_CLIENT_ID,
			clientSecret: GOOGLE_CLIENT_SECRET
		})
	],
    secret: AUTH_SECRET,
});
薄田達哉 / tatsuyasusukida薄田達哉 / tatsuyasusukida

レイアウトを忘れていた

src/routes/+layout.server.ts
import type { LayoutServerLoad } from "./$types";

export const load: LayoutServerLoad = async (event) => {
    return {
        session: await event.locals.getSession()
    }
}


これで無事に表示されるようになった。

薄田達哉 / tatsuyasusukida薄田達哉 / tatsuyasusukida

これで終わりだが

せっかくなので認証されたユーザー向けのページを作ってみよう。

コマンド
mkdir src/routes/authenticated
touch src/routes/authenticated/+page.svelte
src/routes/authenticated/+page.svelte
<h1>This page is for authenticated users only</h1>
薄田達哉 / tatsuyasusukida薄田達哉 / tatsuyasusukida

認証を必須にする

src/hooks.server.ts
import { SvelteKitAuth } from '@auth/sveltekit';
import Google from '@auth/core/providers/google';
import { GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET } from '$env/static/private';
import { redirect, type Handle } from '@sveltejs/kit';
import { sequence } from '@sveltejs/kit/hooks';

const authorization: Handle = async ({ event, resolve }) => {
    if (event.url.pathname.startsWith('/authenticated')) {
        const session = await event.locals.getSession();
        if (!session) {
            throw redirect(303, '/');
        }
    }

    return resolve(event);
}

export const handle = sequence(
    SvelteKitAuth({
        providers: [
            Google({
                clientId: GOOGLE_CLIENT_ID,
                clientSecret: GOOGLE_CLIENT_SECRET
            })
        ],
    }),
    authorization
);

これでログインしていない状態で /authenticated にアクセスするとリダイレクトされるようになる。

薄田達哉 / tatsuyasusukida薄田達哉 / tatsuyasusukida

ユーザー識別子

頑張ればサブジェクトも取得できるがそうでなければメールアドレスを使えば十分そうだ。

src/hooks.server.ts
import { SvelteKitAuth } from '@auth/sveltekit';
import Google from '@auth/core/providers/google';
import { GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET } from '$env/static/private';
import { redirect, type Handle } from '@sveltejs/kit';
import { sequence } from '@sveltejs/kit/hooks';

const authorization: Handle = async ({ event, resolve }) => {
	if (event.url.pathname.startsWith('/authenticated')) {
		const session = await event.locals.getSession();
		if (!session) {
			throw redirect(303, '/');
		}
	}

	return resolve(event);
};

export const handle = sequence(
	SvelteKitAuth({
		providers: [
			Google({
				clientId: GOOGLE_CLIENT_ID,
				clientSecret: GOOGLE_CLIENT_SECRET
			})
		],
		callbacks: {
			session: ({ session, token }) => {
				console.log(token);
				return session;
			}
		}
	}),
	authorization
);
薄田達哉 / tatsuyasusukida薄田達哉 / tatsuyasusukida

おわりに

比較的スムーズに進んで良かった。

機会があれば Auth0 も試してみたい。

今さらだがリポジトリ名を sveltekit-google-auth-example にすればよかった。

薄田達哉 / tatsuyasusukida薄田達哉 / tatsuyasusukida

と思ったけど

API ルートやフォームアクションで parent() 関数を使えないことを考えるとやっぱり locals を使った方が良いかも知れない。

このスクラップは5ヶ月前にクローズされました