IdentityServer4+redux-oidc报错:客户端未配置通过浏览器接收AccessToken
解决IdentityServer4与redux-oidc集成的"Client requested access token - but client is not configured to receive access tokens via browser"错误
先梳理下你当前的配置和遇到的错误:
你的IdentityServer4客户端配置
new Client { ClientId = "openIdConnectClient", ClientName = "Example Implicit Client Application", //AllowedGrantTypes = GrantTypes.Implicit, AllowedGrantTypes = GrantTypes.ClientCredentials, ClientSecrets = { new Secret("secret".Sha256()) }, AllowOfflineAccess = true, AllowAccessTokensViaBrowser = true, AccessTokenLifetime = 30, AllowedScopes = new List<string> { IdentityServerConstants.StandardScopes.OpenId, IdentityServerConstants.StandardScopes.Profile, IdentityServerConstants.StandardScopes.Email, "role", "customAPI.write" }, RedirectUris = new List<string> {"http://localhost:8080/callback"}, PostLogoutRedirectUris = new List<string> {"https://localhost:44330"}, AllowedCorsOrigins = new List<string> { "http://127.0.0.1:8080", "http://localhost:8080", "*" }, }
React应用的userManager配置
import { createUserManager } from 'redux-oidc'; const userManagerConfig = { client_id: 'openIdConnectClient', redirect_uri: `${window.location.protocol}//${window.location.hostname}${window.location.port ? `:${window.location.port}` : ''}/callback`, //response_type: 'code id_token token', response_type: 'token id_token', scope: 'openid profile email role', authority: 'http://localhost:50604', silent_redirect_uri: `${window.location.protocol}//${window.location.hostname}${window.location.port ? `:${window.location.port}` : ''}/silent_renew.html`, automaticSilentRenew: true, filterProtocolClaims: true, loadUserInfo: true, }; const userManager = createUserManager(userManagerConfig); export default userManager;
错误信息
Client requested access token - but client is not configured to receive access tokens via browser
问题根源
你踩了一个典型的授权类型不匹配的坑:
- 你的React应用是浏览器端SPA,用的是Implicit流(
response_type: 'token id_token'),但IdentityServer4的客户端却配置成了GrantTypes.ClientCredentials——这是专门给服务端应用用的授权方式,完全不适合浏览器场景:它不需要跳转、不返回id_token,和你设置的RedirectUris等SPA必备参数完全冲突,自然会触发错误。
解决方案
根据你的场景,推荐两种修复方式,优先选更安全的第二种:
方案1:改用Implicit流(快速适配)
修改IdentityServer4的客户端配置,恢复为Implicit授权类型,同时移除不需要的ClientSecrets(浏览器无法安全存储密钥):
new Client { ClientId = "openIdConnectClient", ClientName = "Example Implicit Client Application", AllowedGrantTypes = GrantTypes.Implicit, // 恢复Implicit流适配SPA // 移除ClientSecrets,Implicit流不需要客户端密钥 AllowOfflineAccess = true, AllowAccessTokensViaBrowser = true, AccessTokenLifetime = 30, AllowedScopes = new List<string> { IdentityServerConstants.StandardScopes.OpenId, IdentityServerConstants.StandardScopes.Profile, IdentityServerConstants.StandardScopes.Email, "role", "customAPI.write" }, RedirectUris = new List<string> {"http://localhost:8080/callback"}, PostLogoutRedirectUris = new List<string> {"https://localhost:44330"}, AllowedCorsOrigins = new List<string> { "http://127.0.0.1:8080", "http://localhost:8080" } // 避免用*,提升安全性 }
对应的React userManager配置,记得把scope加上你允许的customAPI.write:
import { createUserManager } from 'redux-oidc'; const userManagerConfig = { client_id: 'openIdConnectClient', redirect_uri: `${window.location.protocol}//${window.location.hostname}${window.location.port ? `:${window.location.port}` : ''}/callback`, response_type: 'token id_token', scope: 'openid profile email role customAPI.write', // 补充customAPI.write scope authority: 'http://localhost:50604', silent_redirect_uri: `${window.location.protocol}//${window.location.hostname}${window.location.port ? `:${window.location.port}` : ''}/silent_renew.html`, automaticSilentRenew: true, filterProtocolClaims: true, loadUserInfo: true, }; const userManager = createUserManager(userManagerConfig); export default userManager;
方案2:改用Authorization Code + PKCE流(更安全,推荐)
Implicit流现在已经不是SPA的最佳实践,推荐用授权码流配合PKCE(Proof Key for Code Exchange),安全性更高:
修改IdentityServer4客户端配置:
new Client { ClientId = "openIdConnectClient", ClientName = "Example SPA Client Application", AllowedGrantTypes = GrantTypes.Code, // 切换为授权码流 RequireClientSecret = false, // SPA不需要客户端密钥 AllowPkce = true, // 启用PKCE增强安全 AllowOfflineAccess = true, AllowAccessTokensViaBrowser = true, AccessTokenLifetime = 30, AllowedScopes = new List<string> { IdentityServerConstants.StandardScopes.OpenId, IdentityServerConstants.StandardScopes.Profile, IdentityServerConstants.StandardScopes.Email, "role", "customAPI.write" }, RedirectUris = new List<string> {"http://localhost:8080/callback"}, PostLogoutRedirectUris = new List<string> {"https://localhost:44330"}, AllowedCorsOrigins = new List<string> { "http://127.0.0.1:8080", "http://localhost:8080" } }
对应的React userManager配置,修改response_type为code,并补充offline_access用于刷新令牌:
import { createUserManager } from 'redux-oidc'; const userManagerConfig = { client_id: 'openIdConnectClient', redirect_uri: `${window.location.protocol}//${window.location.hostname}${window.location.port ? `:${window.location.port}` : ''}/callback`, response_type: 'code', // 授权码流对应响应类型 scope: 'openid profile email role customAPI.write offline_access', // 补充offline_access用于令牌刷新 authority: 'http://localhost:50604', silent_redirect_uri: `${window.location.protocol}//${window.location.hostname}${window.location.port ? `:${window.location.port}` : ''}/silent_renew.html`, automaticSilentRenew: true, filterProtocolClaims: true, loadUserInfo: true, }; const userManager = createUserManager(userManagerConfig); export default userManager;
内容的提问来源于stack exchange,提问作者Dayan
相关产品推荐
相关产品推荐

