如何使用jwt在nodejs后端验证Auth0中的令牌?JsonWebTokenError

qvk1mo1f  于 2023-02-03  发布在  Node.js
关注(0)|答案(1)|浏览(206)

我有一个使用auth0的react前端来记录用户,一旦用户登录,我就使用getAccessTokenSilently()获取令牌,并将其发送到后端,如下所示:

const { user, isAuthenticated, getAccessTokenSilently } = useAuth0()

useEffect(() => {
    if (user) getTickets()
}, [user])

async function getTickets() {
    const token = await getAccessTokenSilently()
    const response = await fetch('http://localhost:4000/api/gettickets', {
        method: 'POST',
        headers: {
            Authorization: `Bearer ${token}`,
            'Content-Type': 'application/json',
        },
        body: JSON.stringify({ user, bar }),
    })
    const data = await response.json()
}

一旦我的后端有了令牌,我就尝试验证它jsonwebtoken如下:

import express from 'express'
import jwt from 'jsonwebtoken'
import dotenv from 'dotenv'
dotenv.config()

const routerGetTickets = express.Router()

routerGetTickets.post('/', async (req, res) => {
    const PUBKEY = process.env.PUBKEY
    const token = req.headers.authorization?.split(' ')[1]

    if (token && PUBKEY) {
        jwt.verify(token, PUBKEY, { algorithms: ['RS256'] }, (err, data) => {
            console.log('token :>> ', token)
            if (err) {
                res.sendStatus(403)
                console.log('err :>> ', err)
                return
            } else {
                console.log('everything ok')
            }
        })
    }
})
export default routerGetTickets

如果我没有错的话,对于RS256算法,我必须提供我使用openssl获得的公钥,以及我从Auth0 Jmeter 板中的应用程序下载的登录证书。
这是我得到的错误:err :>> JsonWebTokenError: secretOrPublicKey must be an asymmetric key when using RS256
这是我的索引

import React from 'react'
import ReactDOM from 'react-dom/client'
import './sass/index.scss'
import App from './App'
import { BrowserRouter } from 'react-router-dom'
import { Auth0Provider } from '@auth0/auth0-react'

const root = ReactDOM.createRoot(document.getElementById('root') as HTMLElement)

root.render(
<React.StrictMode>
    <BrowserRouter basename='/tombola'>
        <Auth0Provider
            domain='*******.uk.auth0.com'
            clientId='*****************************'
            authorizationParams={{
                redirect_uri: `${window.location.origin}/tombola/callback`,
                audience: 'https://******.uk.auth0.com/api/v2/',
                scope: 'read:current_user update:current_user_metadata'

            }}
        >
            <App />
        </Auth0Provider>
    </BrowserRouter>
</React.StrictMode>
)
dtcbnfnu

dtcbnfnu1#

我在使用Auth 0的Verify JWT方法中也遇到了这个问题,问题出在公钥上。
你没有显示你的.env文件中PUBKEY变量的位置,但是我想你是从应用程序-〉设置-〉高级设置-〉证书中得到的,就像Auth 0文档说的那样,但是那是证书而不是公钥。
要获取公钥,您需要使用“jwks-rsa”库,它使用证书检索公钥,从Auth 0应用程序域获取公钥,为此它需要两件事:
1-用于构造Auth 0提供密钥的url的域。
2-你的jwt令牌的“kid”头,它标识了正确的密钥。
代码如下所示:

async function HandleRequest(req, res) {
const cookie = req.headers.cookie;

const token = cookie.split(";")
.find(c => c.trim().startsWith("access_token="))
.split("=")[1]

const kid = decode(token, { complete: true }).header.kid;

const publicKey = (await JwksRsa({
    cache: true,
    rateLimit: true,
    jwksRequestsPerMinute: 5,
    jwksUri: `https://${process.env.DOMAIN}/.well-known/jwks.json`
}).getSigningKey(kid)).getPublicKey()

if (cookie && cookie.includes("access_token")) {
    verify(
        token,
        publicKey,
        {
            algorithms: ["RS256"],
        },
        (err, decoded) => {
            if (err) {
                res.write(JSON.stringify(err));
            } else {
                res.write(JSON.stringify(decoded));
            }
        }
    );
} else {
    res.write("No access token found")
}
res.end();
return
}

请注意,在本例中,我使用API路由,处理请求并获取标头中的jwt令牌,我的jwt在标头中为“access_token”,您的jwt可能不同,然后对其进行解码,提取子标识符,将其与域构造的URL一起传递给jwks-rsa,然后jwks-rsa库处理从Auth 0应用程序获取证书的所有请求。以及从证书中检索公钥的所有加密工作。

你可以使用“crypto”节点模块从证书中检索,但我试过了,它是一个烂摊子,因为它与.pem文件比与字符串更好地工作,但它是一个有用的东西知道.
希望这对你有帮助,我知道auth 0在学习的时候会把我们的头脑搞得一团糟。

相关问题