LoginSignup
kinakomoti-t
@kinakomoti-t

Are you sure you want to delete the question?

If your question is resolved, you may close it.

Leaving a resolved question undeleted may help others!

We hope you find it useful!

JWTのデコードしたデータについて

解決したいこと

・Node.js
・MongoDB
・Typescript
・mongooseライブラリ
・Expressフレームワーク
・jsonwebtoken
を使用し、ログイン機能を実装しています。

解決したいことといたしましては、

  • クライアントから受け取ったJWTトークン(エンコードしたもの)を.verifyでデコードしたJwtTokenDecode を、なぜ以下の書き方でMongoDBから一致する_idのデータを引き出せるのか
    findById(JwtTokenDecode)
    
  • findById(JwtTokenDecode._id)だと_idに赤線が入りエラーが吐かれ処理が落ちるのか
    エラーの内容:プロパティ '_id' は型 'string | JwtPayload' に存在しません。
           プロパティ '_id' は型 'string' に存在しません。ts(2339)

該当するソースコード

import { Request, Response, NextFunction } from 'express';
import JWT from 'jsonwebtoken';
import { User } from '../models/user';

// クライアントから渡されたJWTが正常か
export const jwtTokenDecode = (req: Request) => {
  const bearerHeader = req.headers['authorization'];
  if (bearerHeader) {
    const bearer = bearerHeader.split(' ')[1];
    try {
      // .verifyでデコードする
      const jwtDecodedToken = JWT.verify(
        bearer,
        process.env.JWT_TOKEN_SECRET_KEY ?? ''
      );
      return jwtDecodedToken;
    } catch (error) {
      console.log('JWTTokenError', error);
      return false;
    }
  }
};

// JWT認証を検証
export const verifyToken = async (
  req: Request,
  res: Response,
) => {
  const JwtTokenDecoded = jwtTokenDecode(req);

  if (JwtTokenDecoded) {
    // JwtTokenDecodedの型が、 string | JWT.JwtPayload
    // MongoDBから_idが一致するユーザーを取得
    const user = await User.findById(JwtTokenDecoded); 
    if (!user) {
      return res.status(401).json('権限がありません');
    } else {
      req.body.user = user;
    }
  } else {
    return res.status(401).json();
  }
};

処理としては正常に動いているのですが、console.logでJwtTokenDecodedの中身を見たところ、

{ 
 _id: 'デコードされたid(mongodbに保存されている_idと一致)', 
 iat: 1670567743,
 exp: 1670654143 
}

が格納、typeof をしたところ object となっていました。
この場合でいくと、JwtTokenDecoded.idとする必要があると思ったのですが、この形だとエラーを吐かれます。
しかし、JwtTokenDecodedをホバーすると型は、string | JWT.JwtPayloadになっていました。

型がstring | JWT.JwtPayloadだから、findById(JwtTokenDecode)の書き方で、MongoDBからidが一致するデータを取得できると納得はしたのですが、
実際に中身を見るとobjectなのでfindById(JwtTokenDecode._id)しなければいけないのでは?と疑問を感じています。

なぜfindById(JwtTokenDecode._id)ではエラーを吐かれ、findById(JwtTokenDecode)でデータの取得ができるのでしょうか?
拙い文で申し訳ないのですが、ご教示いただけると幸いです。

自分で試したこと

interface MongoUserId {
  _id: string;
}

//省略...

// .verifyでデコードする
const jwtDecodedToken = JWT.verify(
    bearer,
    process.env.JWT_TOKEN_SECRET_KEY ?? ''
) as MongoUserId;

と、型アサーションするとfindById(JwtTokenDecode._id)がエラーにならず正常に動作します。

0

1Answer

フレームワーク的に findById にマジック的な仕組みが働いてるんですかね

JwtTokenDecoded.idとする必要があると思ったのですが、この形だとエラーを吐かれます。

どんなエラーなのでしょうか

1

Comments

  1. @kinakomoti-t

    Questioner
    ありがとうございます!
    私も 「findById にマジック的な仕組み」 を考えているのですが、決定的な記述が見つけられず、「なぜだろう?」となってます..
    エラーとしましては、

    プロパティ '_id' は型 'string | JwtPayload' に存在しません。
    プロパティ '_id' は型 'string' に存在しません。ts(2339)

    と、エラーが出ます。
    ※失礼しました、「JwtTokenDecoded.id」 ではなく 「JwtTokenDecoded._id」でございます。
  2. findById に渡す以前に JwtTokenDecoded._id が呼べてなかったりしないでしょうか?
  3. @kinakomoti-t

    Questioner
    はい、おっしゃる通りJwtTokenDecoded._idは呼べておりません。(._idに赤波線が入り、処理落ちします。)
    ですがJwtTokenDecodedの中身(console.logで表示)としては、objectで
    {
       _id: '~~~',
       iat: 1670567743,
     exp: 1670654143
    }
    となっているのに、
    ・なぜ JwtTokenDecoded._id で呼び出せないのか?
    ・なぜ findById(JwtTokenDecoded) とした時、_idと一致するデータをDBから呼び出せるのか?(Inaura様がおっしゃる様にfindById にマジック的な仕組みがあるのか)
    といった疑問になります。
  4. node で試しましたが普通に呼べますね
    _id が数値ではなく文字列なのは関係なさそうですか?

    const jwt = require('jsonwebtoken')

    const payload = {
    _id: 333,
    name: "Alice",
    email: "example@example.com"
    }

    const token = jwt.sign(payload,'secret_signature')

    console.log(token)

    var decoded = jwt.verify(token, 'secret_signature');
    console.log(decoded._id) // 333
  5. JWT関係なく

    findById({ _id: id })

    という記法でどうなるか試してみるとかどうでしょう
  6. @kinakomoti-t

    Questioner
    ありがとうございます!
    Inaura様のコードを参考にnumber型でも試してみたのですが、

    console.log(decoded._id) // 333

    の箇所の ._id で同じくプロパティが存在しないエラーが出ました。
    _idの型については、文字列・数値は関係ないかと思います。(findByIdの第一引数がany型で、また、MongoDBで自動で生成される_idも文字列なので)
    また、._idでのエラーについては、jsファイルでは出ない且つ、TypeScriptのエラーなので型を付与してあげなければ使えないのかな?と思いながら調べています。

    ご提案いただきました
    findById({ _id: id })
    の記法はJWTでも問題なく通りました!

Your answer might help someone💌