我想知道如何处理Oauth2隐式授予中的刷新令牌 当主要浏览器默认情况下禁用第三方Cookie时,将在2019年开始流动。
一些细节:
当前设置:
ui.example.com
下的UI SPA应用
身份提供者(CloudFoundry的UAA)在uaa.api.example.com
场景:
用户登录时,身份提供商会使用域uaa.api.example.com
的用户详细信息设置cookie,并在重定向的Location
标头中返回JWT。
JWT存储在本地存储中(用于ui.example.com
),但仅在1小时内有效,因此我想刷新它。
prompt=none
发送到IDP授权端点的查询参数,可以刷新(过程在Auth0 guide (it's not UAA but flow is the same中有很好的描述)
uaa.api.exmaple.com/oauth/authorize?prompt=none
的每20m隐藏iframe中创建,这将启动登录过程,而无需用户提供其凭据。流程结束时,响应中返回的新JWT将再次存储在本地存储中。
问题:
当允许使用第三方cookie时,浏览器会将IDP的cookie添加到iframe发出的请求中,因此流程可以正常工作,并且我在响应中获得了新令牌。
在浏览器的设置中禁用了第三方Cookie时,iframe无法访问自己的Cookie,因此返回错误login_required
而不是新的JWT。 iframe无法访问Cookie使得无法使用令牌续签
问题:
我的第三方Cookie是否有解决方案?
如果没有,我是否可以使用隐式授权流程和SPA替代方案来登录和刷新令牌?
答案 0 :(得分:0)
作为您的应用程序和身份服务器托管在另一个域中。这意味着您的应用程序正在执行跨域身份验证。跨域身份验证是使用第三方Cookie来实现的,禁用第三方Cookie会使跨域身份验证失败。
回答您的问题:
我的第三方Cookie是否有解决方案?
在同一目录下托管您的应用程序和身份服务器 域。在这种情况下,您可以使用子域。
如果没有,我是否可以使用隐式授权流程和SPA替代方案来登录和刷新令牌?
否
解决方案:
我对CloudFoundry不熟悉。不确定他们是否支持。您可以通过在身份提供者端启用自定义域来解决此问题。因此,您的应用程序和身份提供者都将在同一个域中,并且cookie被视为第一方。例如,将应用程序托管在https://acme.com并将身份提供者自定义域设置为https://login.acme.com
答案 1 :(得分:0)
问题:
我的第三方Cookie是否有解决方案?
如果您在应用程序和IDP之间使用相同的顶级域,那么禁用第三方Cookie时应该没有问题。 This link还详细介绍了使用跨域策略获得成功的情况。
如果没有,则是否有隐式补助金流程和SPA的替代方案 我可以用来登录和刷新令牌?
我以前没有使用过CloudFoundry,但是大多数大型OAuth2.0提供程序都提供了公共客户端功能,其中公共客户端(例如您的SPA)不需要客户端密码来获取访问/刷新令牌。这使公共客户端可以使用Authorisation Code Grant,它可以允许通过刷新令牌来刷新令牌,从而避免了使用HTTP重定向和cookie的 silent auth 技术。
答案 2 :(得分:0)
问题的根源是使用iframe
和隐式授予类型。
我认为您使用iframe的原因是跨域访问Cookie。现在,避免使用iframe
的最简单方法是将cookie的域设置为Domain=example.com
,并在example.com
上同时具有UI和授权服务器。如果由于某种原因您不能执行此操作,则需要采用以下方法。
隐式授予类型不安全。尽管此问题与赠款类型的优缺点无关,但为了设置我将要解释的选项的背景,让我简要列举一下为什么我认为隐式流程不安全的原因:
因此,建议的选项是使用授权码授予类型。在SPA(单页应用程序)中不使用授权码的原因之一是,它要求将客户端机密存储在浏览器中,并且我们知道浏览器无法保存机密。通过在服务器端具有代理组件(可以嵌入到资源服务器中)来保护客户端机密并充当SPA与授权服务器之间的代理,可以非常轻松地减轻这种风险。
(在授权码授予类型中)流程如下:
用户输入其凭据,然后单击“登录”按钮。用户名和密码将使用HTTP POST发送到授权服务器。凭据应在请求正文或标头中发送,而不应在URL中发送(因为URL已记录在浏览器历史记录和应用程序服务器中)。另外,应设置适当的缓存HTTP标头,以便不缓存凭据:Cache-Control:不缓存,不存储,Pragma:不缓存,Expires:0
授权服务器根据用户数据库(例如LDAP服务器)对用户进行身份验证,在该数据库中,用户名和用户密码的哈希(哈希算法(如Argon2,PBKDF2,Bcrypt或Scrypt)与随机盐一起存储)
Domain=example.com
来设置适当的Cookie,从而将用户(HTTP响应代码302)重定向到SPA URL(假设资源服务器和UI都位于的子域中) example.com
)。授权服务器的域无关紧要,因为它没有设置任何cookie。以相同的方式,访问令牌刷新的请求可以发送到代理组件,该代理组件将从cookie中读取刷新和访问令牌,并使用由此提取的令牌,客户端ID和客户端调用授权服务器api。客户机密。
答案 3 :(得分:0)
最后,我们决定采用其他解决方案。当JWT生命周期结束时,我们显示一个模式通知会话已超时,并带有2个按钮,一个按钮用于注销,另一个按钮用于保持会话。当用户单击“保留会话”时,将打开新的选项卡/弹出窗口,在该选项卡中,可以通过再次提供其凭据或在IDP会话仍处于活动状态时自动提供其凭据来在IDP中对用户进行重新认证。
所以流程是:
JWT lifetime ends
-> 'keep session' in modal chose
-> open new tab/popup-window with IDP login form
-> successfully authenticated
-> redirect back to app
-> store token in browser's storage
-> close popup-window/tab with window.close()
-> get new token from storage and use it in next calls
由于我们使用新的弹出窗口/选项卡重新进行身份验证,因此第三方Cookie没问题。
这也提供了一个巨大的优势。用户无论何时回到应用程序都不会失去工作,因为模式将在那里等待。我认为,此外,它还使我们满足了Re-authenticing accessibility success criterion (level AAA)
成功标准2.2.5重新认证
经过身份验证的会话到期时,用户可以在重新进行身份验证后继续活动,而不会丢失数据。