NextAuthを使ったDiscord認証

# NextAuthを使ったDiscord認証

NextAuthを利用することで簡単にDiscord認証を実装できるので、その紹介になります。
基本的には公式ドキュメントを参考にしていますので、詳しくはそちらをご覧ください。

https://next-auth.js.org/providers/discord  


:::note warn
今回使っているnext-authのバージョンは、"next-auth": "^5.0.0-beta.19" です。
:::

<br?>
## Discord Developer側の準備
https://discord.com/developers/docs/topics/oauth2

- #### アプリケーションの作成
  上記の公式ドキュメントにもありますが、まずはAuth認証用のアプリケーションを作ります
![1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3832781/3b04aeb0-bb03-8a5d-a562-a62be387a8ca.png)
<br>

- #### ID,SECRETの所得
  OAuth2の項目から **CLIENT ID**, **CLIENT SECRET** を取得します
:::note info
後で**CLIENT ID**, **CLIENT SECRET**を使いますのでメモしておきましょう。
:::
<br>

- #### Redirectsの設定
  同じOAuth2の項目のRedirectsを下記のように設定
  ![2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3832781/808a9516-8750-6c5d-5181-8306c5c216c4.png)
  ```http://localhost:3000/api/auth/callback/discord```



<br?>
## Next.js側での処理

:::note warn
Authの基本的な書き方は下記の動画を参考にしましたので、詳しくはそちらをどうぞ。
https://www.youtube.com/watch?v=2xexm8VXwj8
:::


```.env
//  example-project/.env

AUTH_SECRET = ****** 
AUTH_URL=http://localhost:3000/api/auth

AUTH_DISCORD_ID     =  先ほど取得したID
AUTH_DISCORD_SECRET =  先ほど取得したSECRET
```


```auth.ts
//  example-project/auth.ts

import NextAuth from "next-auth";
import Discord from "next-auth/providers/discord"
 
export const { handlers, auth, signIn, signOut } = NextAuth({
    providers: [Discord({
        clientId:     process.env.AUTH_DISCORD_ID     as string,
        clientSecret: process.env.AUTH_DISCORD_SECRET as string
    })],
    basePath: "/api/auth",
    callbacks: {
        authorized({request, auth}){
            try{
                const {pathname} = request.nextUrl;
                if(pathname === "/protected-pge") return !!auth;
                return true;
            } catch(err) {
                console.log(err);
            }
        },

        jwt({ token, trigger, session, account}) {
            if(account){
                // 初回の認証時に実行
                token.id = account.providerAccountId
            }
            
            if(trigger === "update") token.name = session.name;
            return token;
        },

        session({ session, user, token }) {
            session.user.id = token.id as string
            return session
        },
    },
    session: {
        // sesstionTime (second)
        maxAge: 600
    }
})  
```

```serverAction.ts
//  example-project/app/serverActions/serverAction.ts

"use server";

import { signIn } from '@/auth';

export async function handleSignin() {
  await signIn("discord");
}
```

```tsx
//  example-project/app/compose/SigninButton/SigninButton.tsx

import React from 'react'

import { handleSignin } from '../../serverActions/serverAction';

export default async function SigninButton() {
    return(
        <form action={handleSignin}>
            <button type='submit'>
                Signin
            </button>
        </form>
    );
}
```

```tsx
//  example-project/app/compose/UserButton/UserButton.tsx
import React from 'react'

import { auth } from "@/auth";

import SigninButton from "../SigninButton/SigninButton";
import layout from "./userButton.module.scss";

export default async function UserButton() {
    const session = await auth();

    let imgPath = "https://upload.wikimedia.org/wikipedia/commons/2/2e/Microsoft_Account_Logo.svg"

    //sesstionが無ければsigninを表示
    if(! session?.user) return <div><SigninButton/><img className={layout.userAccountImg} src={imgPath} /></div>;

    imgPath = session.user.image as string
    return(
        <div>
            <img className={layout.userAccountImg} src={imgPath} />
            <pre>
                {JSON.stringify(session, null, 2)}
            </pre><br />
        </div>
    );
}
```



```route.ts
//  example-project/app/api/auth/[...nextauth]/route.ts

import { handlers } from "@/auth";

export const { GET, POST } = handlers;
```

```middleware.ts
//  example-project/middleware.ts

export {auth as middleware } from "@/auth";

export const config = {
    // matcher: "/profile:",
};
```
<br?>

## 認証時の実行結果
![3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3832781/0fe0b8f6-05e0-8f24-5508-674b820e5e11.png)


## 最後に
今回の紹介したコードに加えたプロジェクトをgithubに公開していますので、参考までにどうぞ。

https://github.com/kosupe/nextAuthTest