OAuth授权后如何向客户端发送jwt令牌?

Posted

技术标签:

【中文标题】OAuth授权后如何向客户端发送jwt令牌?【英文标题】:How can i send jwt token to client after OAuth autherization? 【发布时间】:2020-11-22 01:17:02 【问题描述】:

我正在尝试使用 GitHub OAuth 对用户进行身份验证,而对于普通用户,我正在使用 jwt 令牌。

在我的流程中,用户按下“使用 github 登录”按钮,然后按照 Github 文档 - 用户重定向到 github 网络以选择他的帐户。

所以这是我客户端的主要代码:

function SocialLogin(props)  

    const githubAuth = async (e) =>
        e.preventDefault()
        const githubOAuthURL = 'http://localhost:5000/api/oauth/github';
        let githubTab = window.open(githubOAuthURL, '_self');
        githubTab.focus();
      

  return (
    <div>
        <div className="right-box-inner"></div>
        <div className="wrap-buttons">
            <div className="signwith">Sign in with Social Network</div>
            <button onClick=githubAuth className="social github"><i className="fab fa-github"></i>    Log in with Github</button>
        </div>
    </div>
  )

在我的服务器端,客户端请求的路由“api/oauth/github”是:

router.get('/github', async (req,res) => 
    try
    res.redirect('https://github.com/login/oauth/authorize/?client_id='+config.get('githubClientId'))
    
    catch(err)
        console.log(err.response)
    
)

所以在https://github.com/login/oauth/authorize/?client_id='+config.get('githubClientId')被执行之后,并且正确地选择了他的账户,我在githubaccount的应用程序设置中定义的回调url,执行:

router.get('/github/callback', async (req,res) => 
    const query = req;
    const code = query.code;
    try
        if(!code)
          return res.status(404).json(msg : 'Autherization failed')
        else
          const gitAuthDetails = 
            client_id: config.get('githubClientId'),
            client_secret: config.get('githubSecret'),
            code: code
            
        
          const headers = 
            headers: 
                'Content-Type': 'application/json;charset=UTF-8',
                "Access-Control-Allow-Origin": "*",
            
          
          const response=await axios.post('https://github.com/login/oauth/access_token',gitAuthDetails,headers)
          access_token=response.data.split('=')[1].split('&')[0]

          const userResponse=await axios.get('https://api.github.com/user', headers:  Authorization: 'token ' + access_token  )

          //Lets asssume that i store here a new user to my DB with the all github details e.g username, email ...
          // and create a payload for jwt.
          // Now i want to generate new JWT for the new user , and problem is here. to where i need send my token? 
          // there is any function in my client side that listening and waiting for response.
            jwt.sign(
                payload,
                config.get('jwtSecret'),
                expiresIn:360000,
                (err,token) => 
                    if(err) throw err;
                    //What i need to do with my token?
                    res.redirect('http://localhost:3000/dashboard')
                
            );


        
    
    catch(err)
    console.log(err)
    res.redirect('http://localhost:3000/login')
    
)

正如我在代码中描述的那样,我的令牌被困在这里,我想将它发送到客户端,然后将我的令牌存储到 localStorage。

一些建议?

【问题讨论】:

【参考方案1】:

将令牌存储在本地存储中并不是最佳做法,因为它不安全。如果您有后端 API,最好使用 OAuth 2.0 授权代码流来确保访问令牌的安全性。

这需要使用 OAuth 服务器 (github) 通过登录页面获取授权码。然后将代码传递给您的 API,并在更受信任的“反向通道”(在您的 API 和 OAuth 服务器之间)交换用于身份验证的实际访问令牌。 OAuth 服务器会知道你是谁,因为你会使用你的 ClientId 和 ClientSecret 来查询令牌(在 javascript 中存储 ClientId 和 ClientSecret 也是不安全的)

这意味着令牌将存储在您的服务器上,您需要在 API 上提供端点以获取所需的数据。

Here 是一个很好地解释了这一点的视频。

【讨论】:

不是说你的服务器变成有状态了吗?它与 REST 方法兼容吗?我对此有点困惑,我不明白为什么客户端不能拥有 access_token,例如通过 cookie。 是的。您可以使用数据库来存储令牌,或者在内存缓存中,如Redis。或者,如果您运行的 API 不是持久的,您可以使用第三方缓存提供程序,例如 AWS ElastiCache。您可以使用httpOnlyCookies,这比将它们存储在本地存储中更安全。但是您仍然会将您的 ClientId 和 SecretId 存储在 Javascript 代码中,这是不可取的 我认为您不会将 clientId/secretId 存储在 JS 中,因为我仍然可以拥有一个服务器来处理身份验证过程本身。我只谈论令牌本身,我宁愿将其提供给客户端,以保持应用服务器完全无状态。

以上是关于OAuth授权后如何向客户端发送jwt令牌?的主要内容,如果未能解决你的问题,请参考以下文章

OAuth2.0-JWT令牌

Spring Boot:在标头中发送 JWT(OAuth)

OAuth2:JWT授权授予和客户端凭据授权与JWT客户端身份验证之间的区别是什么?

服务器如何在基于令牌的授权中将 JWT 发送给客户端?

Spring Webflux SecurityValidate OAuth2 JWT 令牌

如何在不访问身份验证服务器的情况下验证 OAuth2 访问令牌 (JWT)