Nest.jsでGoogle認証(OAuth2.0)を使う【フロントエンド編】
に公開
こちらは前回の記事のフロント側の実装になります。
ポイントとしては、
①Googleログイン後にid_tokenとrefresh_tokenを取得する
②id_tokenが有効期限(1時間)を過ぎていた場合はrefresh_tokenを使用し、id_tokenを再取得する
※ 今回はauth-optionsのみの説明になります
auth-options
import GoogleProvider from 'next-auth/providers/google';
import type { NextAuthOptions, Session } from 'next-auth';
export const authOptions: NextAuthOptions = {
debug: true,
session: { strategy: 'jwt' },
providers: [
// 1) providers内でGoogleProviderを指定する
GoogleProvider({
clientId: process.env.GOOGLE_CLIENT_ID!,
clientSecret: process.env.GOOGLE_CLIENT_SECRET!,
authorization: { params: { access_type: 'offline', prompt: 'consent' } },
}),
],
callbacks: {
async jwt({ token, account }) {
if (account) {
/*
2) 初回ログイン後はこちらの処理が走ります。accountにGoogleの認証サーバーから取得した情報が入ってきます。
id_tokenとrefresh_tokenをproviderに持たせます
*/
return {
access_token: account.access_token,
expires_at: account.expires_at,
refresh_token: account.refresh_token,
user: token,
id_token: account.id_token,
};
} else if (Date.now() < (token.expires_at as number) * 1000) {
// 3) id_tokneの有効期限(1時間)内の場合
return {
...token,
};
} else {
if (!token.refresh_token) throw new Error('Missing refresh token');
// 4) id_tokenの期限切れの場合
try {
const urlSerchParamsArgs: Record<string, string> = {
client_id: process.env.GOOGLE_CLIENT_ID!,
client_secret: process.env.GOOGLE_CLIENT_SECRET!,
grant_type: 'refresh_token',
refresh_token: token.refresh_token as string,
};
// 5) id_tokenを再取得しに行きます
const response = await fetch('https://oauth2.googleapis.com/token', {
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: new URLSearchParams(urlSerchParamsArgs),
method: 'POST',
});
const tokens = await response.json();
if (!response.ok) throw tokens;
return {
...token,
access_token: tokens.access_token,
expires_at: Math.floor(Date.now() / 1000 + tokens.expires_in),
refresh_token: tokens.refresh_token ?? token.refresh_token,
id_token: tokens.id_token,
};
} catch (error) {
console.error('Error refreshing access token', error);
return { ...token, error: 'RefreshAccessTokenError' as const };
}
}
},
session: ({ session, token }: { session: Session; token: any }) => {
return {
...session,
user: {
name: token?.user?.name,
email: token.user.email,
image: token.user.picture,
role: token.role,
id_token: token.id_token,
},
};
},
},
};
このようにすることで1時間以内のid_tokenを保持することができます