Identity Server 4:Postman可获取AccessToken,代码调用报invalid_grant
Identity Server 4 代码调用返回
invalid_grant 但Postman正常的问题 问题现象
基于Identity Server 4实现OAuth认证后,Postman中发起认证请求可正常获取AccessToken、Token Type、id_token、expires_in等信息,且能使用该AccessToken访问受保护API。但通过代码实现相同流程时,却返回invalid_grant错误。
认证流程
- 调用API设置患者上下文,将患者ID和GUID保存到数据库,该GUID作为
launch参数值。 - 调用自定义
/auth端点,传入Identity Server 4(ID4)/connect/authorize所需的所有参数及额外的launch参数以维持患者ID上下文,请求参数包含:client_id=client、response_type=code、scope=openid profile myAPI、client_secret=secret、state=1234567890p、aud=https://api.location.com、launch=K123K456Y7777、redirect_uri=https://test.azurewebsites.net/auth。该端点会在数据库中关联state与launch值以维持上下文。 - 上述端点随后调用ID4的
/connect/authorize端点并传入对应参数,在认证流程中再次将sessionId与state关联以维持上下文。 - ID4的
/connect/authorize端点按预期返回授权码(authorization code)、scope、state及session_state。 - 在上述authorize请求指定的redirectURI的Get方法中,获取授权码并向ID4的
/connect/token端点发起标准POST请求。 - 请求返回
invalid_grant错误。
以上流程在Postman中完全正常。
已配置的代码与参数
客户端配置
new Client { ClientId = "client", ClientSecrets = { new Secret("secret".Sha256()) }, //RequireClientSecret = false, //false is default RequirePkce = false, //to prevent 'code challenge required' message from appearing when using 'Code' AllowedGrantTypes = GrantTypes.Code ,//{ "code", "authorization_code" },// // where to redirect to after login RedirectUris = { "https://IDS4.azurewebsites.net/signin-oidc", "https://test.azurewebsites.net/auth", "https://test.azurewebsites.net/token", "https://IDS4.azurewebsites.net/Account/Login" }, // where to redirect to after logout PostLogoutRedirectUris = { "https://IDS4.azurewebsites.net/signout-callback-oidc" }, AllowedScopes = new List<string> { IdentityServerConstants.StandardScopes.OpenId, IdentityServerConstants.StandardScopes.Profile, "myAPI" } }
Startup代码
public void ConfigureServices(IServiceCollection services) { services.AddControllersWithViews(); services.AddDbContextPool<AppDbContext>(options => options.UseSqlServer(Configuration.GetConnectionString("DBConnection"))); var builder = services.AddIdentityServer() .AddInMemoryIdentityResources(Config.IdentityResources) .AddInMemoryApiScopes(Config.ApiScopes) .AddInMemoryClients(Config.Clients) .AddTestUsers(TestUsers.Users) .AddCustomTokenRequestValidator<CustomTokenRequestValidator>() .AddCustomAuthorizeRequestValidator<CustomAuthorizeRequestValidator>(); builder.AddDeveloperSigningCredential(); services.AddAuthentication() .AddGoogle("Google", options => { options.SignInScheme = IdentityServerConstants.ExternalCookieAuthenticationScheme; options.ClientId = "<insert here>"; options.ClientSecret = "<insert here>"; }); services.AddMvc() .SetCompatibilityVersion(CompatibilityVersion.Version_3_0).AddXmlSerializerFormatters() .AddMvcOptions(options => options.EnableEndpointRouting = false); services.AddScoped<IDebugRepository, SQLDebugRepository>(); services.AddScoped<IPatientContextRepository, SQLPatientContextRepository>(); services.AddScoped<IClinicAccessRepository, SQLClinicAccessRepository>(); } public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } app.UseCookiePolicy(new CookiePolicyOptions { HttpOnly = HttpOnlyPolicy.None, MinimumSameSitePolicy = SameSiteMode.None, Secure = CookieSecurePolicy.Always }); app.UseStaticFiles(); app.UseRouting(); app.UseIdentityServer(); app.UseAuthorization(); app.UseEndpoints(endpoints => { endpoints.MapDefaultControllerRoute(); }); }
获取授权码后请求Token的代码
[HttpGet] public async Task<string> Get(string code, string scope, string state, string session_state) { try { string grant_type = "authorization_code"; string redirect_uri = "https://test.azurewebsites.net/token"; //sends the token back to requestor string client_id = "client"; //current stable testing client string baseAddress = $"https://IDS4.azurewebsites.net/connect/token"; string client_secret = "secret"; var client = new HttpClient(); client.BaseAddress = new Uri($"https://IDS4.azurewebsites.net/"); var content = new FormUrlEncodedContent(new[] { new KeyValuePair<string, string>("client_id", client_id), new KeyValuePair<string, string>("client_secret", client_secret), new KeyValuePair<string, string>("grant_type", grant_type), new KeyValuePair<string, string>("code", code), new KeyValuePair<string, string>("redirect_uri", redirect_uri) }); client.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/x-www-form-urlencoded")); var res = await client.PostAsync(baseAddress, content); var resp = await res.Content.ReadAsStringAsync(); return resp; } catch (Exception ex) { return ex.Message + Environment.NewLine + ex.StackTrace ; } }
Token重定向测试代码
[Controller] [Route("Token")] [AllowAnonymous] public class TokenController : Controller { [HttpPost] public string Post([FromForm] string access_token, [FromForm] string token_type, [FromForm] string expires_in, [FromForm] string scope, [FromForm] string patient, [FromForm] string id_token, [FromForm] string oceanSharedEncryptionKey) { TokenResponseModel token = new TokenResponseModel { access_token = access_token, expires_in = expires_in, id_token = id_token, patient = patient, scope = scope, token_type = token_type }; string rslt = JsonConvert.SerializeObject(token); return rslt; } public string Get( string test1) { return test1; } }
当前排查方向
尚未尝试设置签名证书,猜测Postman使用内部证书且已接受,但记不太清。认为缺少证书早该引发问题,但这是正在排查的方向之一。
问题分析与解决方案
核心原因:Redirect URI不匹配
Identity Server 4要求,使用授权码交换token时,传入的redirect_uri必须和获取授权码时/connect/authorize请求中使用的redirect_uri完全一致,否则会直接返回invalid_grant。
你在获取授权码时指定的redirect_uri是https://test.azurewebsites.net/auth,但代码中请求/connect/token时传入的是https://test.azurewebsites.net/token,这就是代码失败、Postman正常的关键原因——Postman中你使用了和授权请求一致的redirect_uri。
修复步骤
修改请求/connect/token时的redirect_uri参数,使其与授权请求中的地址保持一致:
string redirect_uri = "https://test.azurewebsites.net/auth";
其他排查点
- 检查授权码是否被重复使用:授权码是一次性的,重复使用会返回
invalid_grant。 - 验证会话关联逻辑:自定义的
sessionId与state关联逻辑是否存在错误,导致ID4无法验证授权码有效性。 - 开启详细日志:在Startup中添加日志配置,查看
/connect/token请求的具体错误详情:
services.AddLogging(logging => { logging.AddConsole(); logging.SetMinimumLevel(LogLevel.Debug); });
内容的提问来源于stack exchange,提问作者eric_the_animal
相关产品推荐
相关产品推荐

