0
1

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.

Azure Active Directoryから取得したJWTをNuxt3でVerifyしたい

Posted at

はじめに

なんか丁度いい記事がなかなか見つからなかったので書いてみました。

クライアントがAzure Active DirectoryからJWTを取得して、それを Authorization: Bearer に付与してリクエストしてくるケースにおいて、受け側のAPIでJWTのVefiryをしたい

これをどうやるのが良さそうか・・・と色々調べたんですが、ジャストフィットするようなサンプルが見つからなかったので。
callbackつかって非同期処理してるやつが多いんですよね。それだと色々とやりにくいんで。

結論

自分はこんな感じで実装しました。なにかの参考になれば。

Nuxt3の server/api/token.get.ts として保存してますので、エンドポイント的には GET localhost:3000/api/token になります。

エラー判定や型は若干(というかかなり)適当です。あくまで主目的が開発ベンダーさんに依頼するためのサンプルだったというのもあり。

import * as jwt from 'jsonwebtoken';
import  jwksClient from 'jwks-rsa'

export default defineEventHandler(async (event) => {
  const req = event.node.req

  const authHeaderValue = req.headers['authorization']
  if (!authHeaderValue) {
    console.log('No authorization header specified')
    return
  }

  var token, 
      tokenHeaderBase64Encoded,
      tokenHeader,
      kid : string

  try {
    // Authorization: Bearer [JWT]となるので、Bearer部分を除外
    token = authHeaderValue.split(' ')[1]
    console.log(`token: ${token}`)

    // Header部(.つなぎの最初)を抽出
    tokenHeaderBase64Encoded = token.split('.')[0]
    console.log(`tokenHeaderBase64Encoded: ${tokenHeaderBase64Encoded}`)

    // Base64デコードしてkid部を抜き出す
    tokenHeader = Buffer.from(tokenHeaderBase64Encoded, 'base64').toString()
    console.log(`tokenHeader: ${tokenHeader}`)

    kid = JSON.parse(tokenHeader).kid
    console.log(`kid: ${kid}`)
  } catch (error) {
    throw createError({
      statusCode: 401,
      statusMessage: 'Token structure is not valid',
      message: error.message || ''
    })
  }

  // 取得したkid部からKey情報を取りに行く
  const client = jwksClient({
    jwksUri: 'https://login.microsoftonline.com/common/discovery/keys'
  })

  var signingKey: string
  try {
    const key = await client.getSigningKey(kid)
    console.log(`key: ${JSON.stringify(key)}`)

    signingKey = key.publicKey || key.rsaPublicKey;
    console.log(`signingKey: ${signingKey}`)
  } catch (error) {
    throw createError({
      statusCode: 401,
      statusMessage: 'Unable to get correct key information from JWT',
      message: error.message || ''
    })    
  }

  const config = useRuntimeConfig()
  console.log(`Runtime Config: ${JSON.stringify(config)}`)

  const verifyOptions = {
    audience: `api://${config.clientId}`
    // audience: 'invalid audience' // for test
  }
  console.log(`Verify Options: ${JSON.stringify(verifyOptions)}`)
  // Verifyメソッドを同期型で呼ぶことでdecode結果直接受領
  try {
    const decoded = jwt.verify(token, signingKey, verifyOptions)
    console.log(`Decoded JWT: (${JSON.stringify(decoded)}`)
    return {
      message: 'JWT has correctly verified'
    }
  } catch (error) {
    throw createError({
      statusCode: 401,
      statusMessage: 'JWT is not valid',
      message: error.message || ''
    })
  }
})
0
1
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
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?