SPA 如何在 OAuth2 隐式流中提取访问令牌

Posted

技术标签:

【中文标题】SPA 如何在 OAuth2 隐式流中提取访问令牌【英文标题】:How does a SPA extract access token in OAuth2 implicit flow 【发布时间】:2018-10-21 10:56:06 【问题描述】:

我有一个基于 Angular 的 SPA,并希望利用 OAuth2 隐式流 OAuth2 implicit flow

当授权服务器建立后,如果我与它有一个活跃的会话并且我发送把这个 URL 放在浏览器地址栏中

https://server.example.com/authorize?response_type=token&client_id=s6BhdRkqt3&state=xyz&redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Fcb HTTP/1.1

我使用 access_token 正确重定向到

 HTTP/1.1 302 Found
 Location: http://client.example.com/cb#access_token=2YotnFZFEjr1zCsicMWpAAs&state=xyz&token_type=example&expires_in=3600
 

规范规定client.example.com/cb 应该返回一个能够访问完整重定向 URI 的网页(通常是带有嵌入脚本的 html 文档),包括用户代理保留的片段,并提取访问令牌。我已经实现了一个页面,脚本从window.location.hash 获取 access_token 并且它可以工作。

现在,由于 SPA 已经加载,而且我还需要为令牌续订执行此操作,因此我想使用 ajax 请求来执行此操作。但是,使用 ajax 时,会自动执行重定向,我只得到 HTML 页面,但 access_token 丢失了。我可以在响应的 Location 标头中看到 access_token,但不知道如何访问它。

Auth0 和Okta 似乎支持使用隐式流的静默身份验证,它们是如何做到的?

任何帮助将不胜感激。

【问题讨论】:

【参考方案1】:

access_token 只能通过location.hash 访问,而 ajax 请求不会更新它,因此无法通过 ajax 请求来实现。

查看了其他库的做法,发现: https://github.com/damienbod/angular-auth-oidc-client#silent-renew

诀窍是创建一个隐藏的iframe,并且每当需要令牌时,将src 属性更新为构造的URL。令牌将在 iframe 中可用,只需将其传递给 window.parent

要实现这一点,首先将一个事件监听器附加到window

window.addEventListener("message", receiveToken, false);

function receiveToken(event) 
  // event.data will contain hash value
  console.log ('token received ' + event.data) ;

并在需要新令牌时调用此函数

function fetchToken() 
    document.getElementById('iframe').src='https://server.example.com/authorize?response_type=token&client_id=s6BhdRkqt3&state=xyz&redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Fcb'

http://client.example.com/cb 应该返回类似这样的内容

<!DOCTYPE html>
<html>
<head>
<script type="text/javascript">
    window.parent.postMessage(location.hash, "http://client.example.com");
</script>
</head>
<body></body>
</html>

这里postMessage 的第二个参数是targetOrigin,它应该匹配托管SPA 的主机名。如果你不想要这个安全限制,可以设置为'*'

【讨论】:

以上是关于SPA 如何在 OAuth2 隐式流中提取访问令牌的主要内容,如果未能解决你的问题,请参考以下文章

OAuth2 隐式流程 - IFrame 刷新身份

在 OAuth 2.0 隐式流中验证​​ nonce 的位置?

是否可以仅请求用户已在 Azure AD OAuth2 隐式流中同意的范围的子集?

自定义声明包含在隐式流中,但不包含在 PKCE 流中

我们真的需要在 OIDC 的隐式流中使用 id_token 吗?

Azure api OAuth2 隐式流适用于 http 但不适用于 htt