1
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Nuxt3(Nitro)backend Server API firebase認証からserver middlewareを使って、認証ルートのみJWTトークンを検証する

Posted at

やりたいこと

Nuxt3バックエンド
APIバックエンドをNuxt3で作る
認証はfirebaseでBearer tokenがクライアント側からくる
認証が必要がルートのみ、Server側でtokenをチェックする
なるべくスマートに実装したい

クライアント側

クライアント側は別に何でも良い。
以下はNuxt2でfirebaseを作ったtwitter認証の例

vue.js
async signin() {
      const provider = new this.$fireModule.default.auth.TwitterAuthProvider()
      await this.$fire.auth
        .signInWithPopup(provider)
        .then(async (result) => {
          const token = await result.user.getIdToken(true)
          this.$axios.setToken(token, 'Bearer')
          this.$axios.$get('/api/authed/me')
        })
        .catch((error) => {
          // Handle Errors here.
        })
    },

Nuxt3 バックエンド側

ポイントだけ押さえたディレクトリ構成
・server/api/authed/** が認証が必要なAPI
・server/api/middleware/auth.tsでtokenを検証
・server/utils/auth.tsでfirebaseに接続(これはどこに置いてもよい)

.
├── server
│   ├── api
│   │   ├── authed
│   │   │   └──  me.get.ts
│   ├── middleware
│   │   └── auth.ts
│   └── utils
│       └── firebase.ts

firebaseに接続

firebase-adminが入ってて、firebaseへの接続設定はうまくいっているものとしますよ。これはNuxt3とは関係ないので省略します。

utils/firebase.ts
import { initializeApp, applicationDefault } from 'firebase-admin/app'
import { getAuth } from 'firebase-admin/auth'
initializeApp({
  credential: applicationDefault()
});
export default function verifyIdToken(token: string) {
  return getAuth().verifyIdToken(token)
}

firebaseのverifyIdToken()がどこからでも使えるようにexportしました。

ミドルウェアを設定する

middlware/auth.ts
import verifyIdToken from '~/server/utils/firebase'
export default eventHandler((event) => {
    if (event.req.url.startsWith('/api/authed')) {
        const token = getRequestHeader(event, 'Authorization').split('Bearer ')[1]
        return verifyIdToken(token).then((decodedToken) => {
            event.context.auth = decodedToken
        }).catch((error) => {
            throw createError({ statusCode: 403, statusMessage: "Forbbiden, Not authenticated."});
        });

    }
});

ここが最大のポイント。Nuxt3のserverMiddlewareで、すべてのAPIリクエストに対して実行する定義を設定します。
ただし、/api/authed以下のみ認証をチェックします。
Authorizationヘッダを取得して、utils/firebase.tsで定義したverifyIdTokenを実行。エラーになった場合は403を返します。
認証が通った場合は、以後の処理側でuserdataを参照できるように、contextへ入れておきます。

認証後ルート

authed/me.ts
export default defineEventHandler((event) => {
    console.log('[Auth?] ' + event.context.auth)
    return event.context.auth
})

認証を通したAPIroute以下では、event.context.authに認証済みユーザーのデータが入っているので、後は煮るなり焼くなり好きにします。

参考

なんかこの辺の実装は自分でやれって感じのスタンスなんですかね、Nuxt3。

↓こんなふうにできたらいいんですけど(現時点ではできません)

export default defineNuxtConfig({
    nitro: {
        routeRules: {
            '/api/authed/***': {
                middleware: AuthedRoutes
            },
        }
    }
});

APIをauthed/以下に分けたくない場合

defineAuthenticatedEventHandlerを作ってラップする方法もあるけど、間違って認証が必要なところでdefineEventHandlerを使ってしまうと認証なしでAPIを通しそうなので怖いのでこちらは採用しませんでした。

1
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?