如何在 ASP.NET Web Forms 中刷新 Okta OIDC token?
结论
在 .NET Framework 4.8 中,可以通过 HttpClient 向 Okta 的 OAuth token endpoint 发送 refresh_token grant 请求。前提是应用已经获得并安全保存 refresh token,且 Okta 应用和授权服务器允许使用 refresh token。
刷新请求可以更新 OAuth token,但未必能解决 ASP.NET 应用在 60 分钟后登出的问题。应用身份验证 cookie、Okta 浏览器会话和 access token 属于不同的会话状态,需要分别排查。
题目描述的是一个使用 Okta.AspNet 的 ASP.NET Web Forms 应用。用户发现,活跃或空闲时都会在约 60 分钟后登出;参考文档则给出了 .NET Core 的调用方式。下面的示例用 .NET Framework 4.8 实现相同的 HTTP 流程。
调用 Okta token endpoint
将 {yourOktaDomain} 替换为 Okta 组织域名,将 {authorizationServerId} 替换为应用实际使用的授权服务器 ID。如果使用默认授权服务器,ID 通常是 default。具体值应以应用的 OIDC 配置为准。
using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Threading.Tasks;
using System.Web.Script.Serialization;
public sealed class TokenRefreshResult
{
public string access_token { get; set; }
public string refresh_token { get; set; }
public string token_type { get; set; }
public int expires_in { get; set; }
}
public static async Task<TokenRefreshResult> RefreshTokenAsync(
string oktaDomain,
string authorizationServerId,
string clientId,
string clientSecret,
string refreshToken)
{
var endpoint = new Uri(
new Uri(oktaDomain.TrimEnd('/') + "/"),
"oauth2/" + authorizationServerId + "/v1/token");
using (var client = new HttpClient())
using (var request = new HttpRequestMessage(HttpMethod.Post, endpoint))
{
var credentials = Convert.ToBase64String(
Encoding.UTF8.GetBytes(clientId + ":" + clientSecret));
request.Headers.Authorization =
new AuthenticationHeaderValue("Basic", credentials);
request.Content = new FormUrlEncodedContent(
new Dictionary<string, string>
{
{ "grant_type", "refresh_token" },
{ "refresh_token", refreshToken }
});
using (var response = await client.SendAsync(request).ConfigureAwait(false))
{
var body = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
response.EnsureSuccessStatusCode();
return new JavaScriptSerializer()
.Deserialize<TokenRefreshResult>(body);
}
}
}
示例使用带 client secret 的机密客户端,并通过 HTTP Basic 发送客户端凭据。客户端认证方式应与 Okta 应用配置一致;如果应用采用其他方式,请相应调整。示例只展示请求和反序列化,未包含异常处理、日志脱敏或 token 持久化逻辑。
安全保存并替换 token
请求成功后,用返回的 access_token 替换旧值。如果响应中包含新的 refresh_token,也应立即替换旧值。启用 refresh token rotation 时,继续使用旧值可能导致后续刷新失败。
应将 token 保存在服务端的受保护存储中,并与相应用户或服务端会话关联。不要把 refresh token 放在浏览器可访问的页面、URL 或客户端存储中,也不要将它写入明文日志。
是否在刷新请求中发送 scope,取决于授权服务器和应用配置。上面的示例没有发送该参数。刷新请求所需的 scope、客户端认证方式和 endpoint 应与当前 OIDC 集成一致。
检查 60 分钟登出原因
先确认过期的是哪一层凭据:
- access token 过期:如果用户仍能访问 Web Forms 页面,只是在调用受保护 API 时失败,可以在 API 调用前后端刷新 access token。
- ASP.NET 身份验证 cookie 过期:刷新 OAuth token 不会自动延长应用 cookie。需要检查 Web Forms 身份验证中间件或应用的 cookie 生命周期和续期设置。
- Okta 浏览器会话过期:用户重新进入授权流程时是否需要再次登录,取决于 Okta 会话和授权请求配置,单次 token 刷新不会自动决定这一点。
如果用户确实被应用登出,应检查应用认证 cookie 的过期时间和续期逻辑,以及 Okta.AspNet 的配置。仅凭“60 分钟”无法判断是 access token 过期。
注意事项
如果应用目前没有拿到 refresh token,仅添加 token endpoint 调用代码还不能完成刷新。需要先确认 OIDC 授权流程和 Okta 配置会签发 refresh token。
刷新失败时,检查 endpoint、授权服务器 ID、客户端认证方式、refresh token 是否仍有效,以及是否已保存 rotation 后返回的新 refresh token。具体配置名称和行为可能因 Okta 应用及授权服务器设置而异,应以当前环境为准。
备注:内容仅供参考。
