Next.jsを用いたWebアプリケーション開発 (2) スコープの設定とアクセス・トークンの取得

[前回](https://qiita.com/BrainVader/items/9d0beea5a7f41e4e2b3e)に続いてNextAuth.jsを用いてGitHubをバックエンドに持つWebアプリケーションを作成していきます.

## 内容

トークンでアクセスできる範囲を[スコープ](https://docs.github.com/en/developers/apps/scopes-for-oauth-apps)とよび指定したスコープでアクセスできる範囲を限定できます. これをリポジトリの操作ができるように変更します. 次にSessionの内容を確認してアクセス・トークンを取得します.

## GitHub認可プロバイダ

### GitHub OAuth Appのスコープ

組み込みの[GitHub認可プロバイダ](https://github.com/nextauthjs/next-auth/blob/main/src/providers/github.js#L7)ではuserに指定されています. userで許されるアクセス範囲は以下です.

> Grants read/write access to profile info only. Note that this scope includes user:email and user:follow.

GitHub APIでリポジトリを操作するには物足りないですね. これをpublic_repoに変更しGitHub APIから操作できるようにします.

> Limits access to public repositories. That includes read/write access to code, commit statuses, repository projects, collaborators, and deployment statuses for public repositories and organizations. Also required for starring public repositories.

[Available scopes](https://docs.github.com/en/developers/apps/scopes-for-oauth-apps#available-scopes)


### GitHub認可プロバイダ型

GitHub認可プロバイダの型を見ると以下のようになっている.

```ts
type GitHub = (options: ProviderGitHubOptions) => GenericReturnConfig;

interface ProviderGitHubOptions {
    clientId: string;
    clientSecret: string;
    scope?: string;
}

interface GenericReturnConfig {
    [key: string]: any;
}
```

scopeはオプション型となっているだけなので指定すれば良いだけのようです.

```js
Providers.GitHub({
    scope: 'public_repo',
    clientId: process.env.GITHUB_ID,
    clientSecret: process.env.GITHUB_SECRET
}),
```

## Access Tokenを探して

### Sessionオブジェクト

[公式の例](https://next-auth.js.org/getting-started/client#example-session-object)では以下のようにaccessTokenが含まれているように見えます.

```javascript
{
  user: {
    name: string,
    email: string,
    image: uri
  },
  accessToken: string,
  expires: "YYYY-MM-DDTHH:mm:ss.SSSZ"
}
```

しかし実際に取得してみると存在しないことが分かります. ドキュメントには

> // Note: `jwt` is automatically set to `true` if no database is specified.

と書いてあります. また[コード](https://github.com/nextauthjs/next-auth/blob/main/src/server/index.js#L130)を見るとデータベースのアダプターがない場合はjwtオプションがtrueに設定されるようになっています.

```js
if (!adapter) {
    sessionOptions.jwt = true
}
```

これらのことからoptionsのdatabaseの設定をコメント・アウトすれば良さそうです.

```js
import NextAuth from 'next-auth'
import Providers from 'next-auth/providers'

const options = {
    // Configure one or more authentication providers
    providers: [
        Providers.GitHub({
            scope: 'public_repo',
            clientId: process.env.GITHUB_ID,
            clientSecret: process.env.GITHUB_SECRET
        }),
        // ...add more providers here
    ],

    // A database is optional, but required to persist accounts in a database
    database: process.env.DATABASE_URL,
}

export default (req, res) => NextAuth(req, res, options)
```

.env.localにDATABASE_URLを指定します.

```
DATABASE_URL=sqlite://localhost/:memory:?synchronize=true
```

synchronizeは[TypeORM](https://typeorm.io/#/)の設定らしいのですが, よく分かりません.

> Setting synchronize makes sure your entities will be synced with the database, every time you run the application.

良く分からないのですがこれがないと動かないのでとりあえずtrueに設定しておくことにします.

最後に必要なsqlite3をインストールしておきます.

```shell
npm i sqlite3
```

セッション・オブジェクトを表示してaccessTokenが含まれていれば取得できています.

## まとめ

ちょっと手こずりましたがアクセス・トークンも取れました. またわからない内容が多くて記事の内容が浅くなってしまいました.

次回はこれを使ってGitHub APIsにアクセスしていきたいと思います.

## 補足

### synchronizeオプション

[Setting up a database](https://next-auth.js.org/configuration/databases#setting-up-a-database)によると,

> The synchronize option should not be used against production databases.

とありプロダクション用途ではこの設定は非推奨です. これはSQLiteもです.

> SQLite is intended only for development / testing and not for production use.

今回はローカル上で動く個人のアプリなのでとりあえずこのまま使っていきたいと思います.

## Further Reading

後で別の記事としてまとめようかと思っている項目です.

### session.js

index.jsの[この部分](https://github.com/nextauthjs/next-auth/blob/8115a7c66cdb1d86b0d2a0d76b9aa33c2bfaa33b/src/server/index.js#L130)と[session.js](https://github.com/nextauthjs/next-auth/blob/8115a7c66cdb1d86b0d2a0d76b9aa33c2bfaa33b/src/server/routes/session.js)を見るとSessionオブジェクトにaccessTokenを含むかを判断するロジックが理解できる.

> Supports both JSON Web Tokens and database sessions

また

> Can also be used without a database (e.g. OAuth + JWT)

[Introduction](https://next-auth.js.org/getting-started/introduction)

### JWT (JSON Web Token)

そもそもJWTとはどんなものなのか?

[Introduction to JSON Web Tokens](https://jwt.io/introduction/)

[Next.js JWT authentication with React Hooks and Context API](https://www.jaygould.co.uk/2020-01-31-nextjs-auth-jwt-context-hooks/

[Using JWT with OAuth2: When and Why](https://www.loginradius.com/engineering/blog/using-jwt-with-oauth2-when-and-why/)

[NextJS and Authentication using OAuth2 and JWT](https://dev.to/whoisryosuke/nextjs-and-authentication-using-oauth2-and-jwt-3gc6)