https にリダイレクトすると Authorization ヘッダーが失われる

はじめに

HttpClient を使って http で Authorization ヘッダー付きのリクエストを送信し、https にリダイレクトされると、https のリクエストには Authorization ヘッダーが付かない。

以下、実験コード。

Web API

HTTP リクエストのヘッダーをログに出力している。リダイレクト前のリクエストヘッダーを確認するために、ログを出力するミドルウェアも挟んでいる。

using System.Text;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;

namespace HttpsRedirectSample
{
    public class Program
    {
        public static void Main(string[] args)
        {
            CreateHostBuilder(args).Build().Run();
        }

        public static IHostBuilder CreateHostBuilder(string[] args) =>
            Host.CreateDefaultBuilder(args)
                .ConfigureWebHostDefaults(webBuilder =>
                {
                    webBuilder.UseStartup<Startup>();
                });
    }

    public class Startup
    {
        public void ConfigureServices(IServiceCollection services)
        {
        }

        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            app.Use(next => context =>
            {
                LogRequestHeaders(context);
                return next(context);
            });

            app.UseHttpsRedirection();

            app.UseRouting();

            app.UseEndpoints(endpoints =>
            {
                endpoints.MapGet("/", async context =>
                {
                    LogRequestHeaders(context);
                    await context.Response.WriteAsync("Hello World!");
                });
            });
        }

        static void LogRequestHeaders(HttpContext context)
        {
            var sb = new StringBuilder();
            foreach (var h in context.Request.Headers)
            {
                sb.AppendLine($"{h.Key}:{h.Value}");
            }

            var logger = context.RequestServices
                .GetService<ILoggerFactory>()
                .CreateLogger("RequestHeaders");
            logger.LogInformation(sb.ToString());
        }
    }
}

Client

適当な値の Authorization ヘッダーを付けて http にリクエストを送信する。

using System;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading.Tasks;

namespace ClientSample
{
    class Program
    {
        static async Task Main(string[] args)
        {
            var httpClient = new HttpClient()
            {
                BaseAddress = new Uri("http://localhost:5000"),
            };
            httpClient.DefaultRequestHeaders.Authorization =
                new AuthenticationHeaderValue("Bearer", "Test");

            var response = await httpClient.GetAsync("/");

            Console.WriteLine(await response.Content.ReadAsStringAsync());
            Console.ReadLine();
        }
    }
}

実行結果

f:id:griefworker:20200521171641p:plain

リダイレクト前にはあった Authorization ヘッダーが、リダイレクト後には含まれていないことを確認できた。

おわりに

IdetityServer4 ホストと、IdetityServer4 が発行するアクセストークンを使って呼び出す Web API を Azure App Service にデプロイしたところ、アクセストークンを付けて Web API を呼び出しているのに 401 が返ってきていた。

IdetityServer4 と Web API 両方ローカルだと上手くいく。IdetityServer4 だけ Azure 上でも上手くいく。両方 Azure 上だとダメ。

検証とはいえアクセストークンの署名に開発用キーを使っているからか?それとも ASP.NET Core の JwtBearer か IdetityServer4 のバグか?と疑ってライブラリのソースコードを調べていたが、原因は Azure 上の Web API を呼び出すときの URL を https ではなく http にしていたからだったとさ。自分のコードが悪かった。

こんな凡ミスに1日半費やしてしまった。自戒を込めてブログに残しておく。