oauth2-proxyでログインなしのアプリにSSOを追加する方法
ログイン機能のないアプリをOIDCで保護する方法を解説します。NginxやTraefikへのoauth2-proxy接続、202と401の判定、Cookieとリダイレクトの落とし穴を確認できます。
前段認証: ログイン機能のないアプリケーションで SSO を実現する方法
oauth2-proxy を使うと、独自のログイン機能を持たないアプリケーションでもシングルサインオンを利用できます。アプリケーションの前段にあるリバースプロキシがすべてのリクエストを停止し、そのリクエストに有効なセッションがあるか oauth2-proxy に確認してから、確認結果が成功の場合だけ上流へ転送するためです。確認処理をアプリケーションが認識することはないため、アプリケーションのコードを変更する必要はありません。
確認には追加の HTTP リクエストを 1 回使用します。プロキシは受信したリクエストヘッダーのコピーを /oauth2/auth に送信し、ステータスコードを読み取ります。202 の場合は呼び出し元にセッションがあるため、プロキシは元のリクエストをアプリケーションへ転送します。401 の場合はセッションがないため、プロキシはブラウザーを /oauth2/sign_in へ転送します。/oauth2/sign_in は、利用している identity provider で OpenID Connect (OIDC) ログインを開始します。OIDC は OAuth 2.0 の上に構築された identity layer で、provider にはログインに使用している既存のサービスを利用できます。
この構成は、各リバースプロキシで異なる名前が付いています。Nginx ではディレクティブ auth_request と呼びます。Traefik では middleware forwardAuth と呼びます。Caddy では forward_auth と表記します。サブリクエストに応答するサービスも任意に選択できます。oauth2-proxy がよく使われるのは、標準の OIDC に対応し、独自のデータベースを必要としないためです。
設定を書く前に、信頼境界を定義する
認証に成功すると、oauth2-proxy はレスポンスヘッダーとして ID を返し、リバースプロキシがそれらを upstream へのリクエストにコピーします。set_xauthrequest を有効にすると、X-Auth-Request-User と X-Auth-Request-Email を利用できます。アプリケーションはこれらのヘッダーを読み取り、信頼します。
これがセキュリティモデルのすべてです。その結果を明確に理解してください。アプリケーションのポートへ TCP 接続できるものは、誰でも自分でこれらのヘッダーを設定し、任意のユーザーになりすませます。curl -H "X-Auth-Request-Email: admin@example.com" http://app-host:3000/ がアプリケーションへ直接到達するだけで、完全なバイパスになります。
したがって、アプリケーションにはプロキシ経由でのみ到達できるようにする必要があります。Docker Compose では、アプリケーションサービスの ports: マッピングを削除し、内部ネットワーク上だけに残します。これにより、接続できるのはプロキシコンテナだけになります。ホスト上で直接実行する場合は、アプリケーションを 0.0.0.0:3000 ではなく 127.0.0.1:3000 にバインドします。次に、実際に公開されている状態を確認します。
sudo ss -tlnp | grep 30000.0.0.0:3000 と表示される行は、アプリケーションがパブリック IP で応答しており、アクセス制御が機能していないことを示します。必要なのは 127.0.0.1:3000 です。ファイアウォールルールは有効な追加防御ですが、別のツールによってルールセットが消去されても維持されるのはバインドアドレスです。
oauth2-proxy のインストール
2026 年 8 月時点の最新リリースは、2026 年 6 月に公開された v7.15.3 です。バイナリをインストールし、ダウンロードを検証します。
cd /tmp
curl -fsSLO https://github.com/oauth2-proxy/oauth2-proxy/releases/download/v7.15.3/oauth2-proxy-v7.15.3.linux-amd64.tar.gz
curl -fsSLO https://github.com/oauth2-proxy/oauth2-proxy/releases/download/v7.15.3/oauth2-proxy-v7.15.3.linux-amd64.tar.gz-sha256sum.txt
sha256sum -c oauth2-proxy-v7.15.3.linux-amd64.tar.gz-sha256sum.txt
tar -xzf oauth2-proxy-v7.15.3.linux-amd64.tar.gz
sudo install -m 755 oauth2-proxy-v7.15.3.linux-amd64/oauth2-proxy /usr/local/bin/oauth2-proxy
oauth2-proxy --versionsha256sum -c の出力は、OK で終わる行にならなければなりません。FAILED と出力された場合は、バイナリを実行せず、再度ダウンロードしてください。
Docker ではイメージは quay.io/oauth2-proxy/oauth2-proxy です。タグを固定してください: quay.io/oauth2-proxy/oauth2-proxy:v7.15.3。latest のままにすると、通常の docker compose pull が、このサーバー上のすべてのアプリを保護するプロセスの意図しないアップグレードになります。
Cookie secret を生成する
セッション Cookie は暗号化され、cookie_secret が暗号鍵になります。値は AES (advanced encryption standard) 鍵として使用されるため、長さを必ず 16、24、または 32 bytes にしてください。これ以外の長さを指定すると、oauth2-proxy は起動を拒否し、Cookie secret に関する起動エラーを出力します。
openssl rand -base64 32 | tr -- '+/' '-_'tr は見た目を整えるためのものではありません。標準の base64 を URL セーフな文字セットに変換するため、値を shell、env ファイル、HTTP ヘッダーで引用符の問題なく扱えます。
この値には2つのルールがあります。デプロイメントごとに異なる secret を使用してください。同じドメインの背後で複数の oauth2-proxy インスタンスを実行する場合は、すべてに同じ secret を設定してください。あるインスタンスが暗号化した Cookie を、他のインスタンスも読み取る必要があるためです。
oauth2-proxy の設定を記述する
長いコマンドラインではなくファイルに設定を保存します。これにより、client secret が ps の出力に表示されなくなります。
# /etc/oauth2-proxy/oauth2-proxy.cfg
http_address = "127.0.0.1:4180"
reverse_proxy = true
provider = "oidc"
oidc_issuer_url = "https://id.example.com/application/o/myapp/"
client_id = "REPLACE_ME"
client_secret = "REPLACE_ME"
redirect_url = "https://app.example.com/oauth2/callback"
cookie_secret = "REPLACE_ME"
cookie_secure = true
cookie_domains = [".example.com"]
whitelist_domains = [".example.com"]
email_domains = ["*"]
set_xauthrequest = true
upstreams = ["static://202"]reverse_proxy = true は、oauth2-proxy に対して、前段のプロキシから渡される X-Forwarded-* ヘッダーを信頼するよう指示します。これがないと、oauth2-proxy はプロキシ自身のアドレスをクライアントアドレスとして扱います。そのため、リクエストが HTTPS で到着したかどうかを誤って判定することがあります。
upstreams = ["static://202"] を指定すると、oauth2-proxy は認証済みのリクエストに対して 202 を返し、プロキシ処理を行いません。これは、リバースプロキシが実際のプロキシ処理を担う forward auth に適した動作です。もう 1 つの構成では、upstreams = ["http://127.0.0.1:3000"] を指定して oauth2-proxy をリクエスト経路に直接配置し、auth_request は指定しません。これは 1 つのアプリケーションには簡単ですが、10 個のアプリケーションには適していません。
email_domains = ["*"] では、プロバイダーが認証するすべてのアドレスを許可します。自分のドメインだけに絞り込んでください。より適切なのは、プロバイダーでグループバインディングを使ってアクセスを制限する方法です。ユーザー管理はすでにプロバイダーで行っているためです。
専用ユーザーで systemd から実行します。
# /etc/systemd/system/oauth2-proxy.service
[Unit]
Description=oauth2-proxy
After=network-online.target
Wants=network-online.target
[Service]
User=oauth2-proxy
Group=oauth2-proxy
ExecStart=/usr/local/bin/oauth2-proxy --config=/etc/oauth2-proxy/oauth2-proxy.cfg
Restart=on-failure
ProtectSystem=strict
PrivateTmp=true
NoNewPrivileges=true
[Install]
WantedBy=multi-user.targetsudo useradd --system --no-create-home --shell /usr/sbin/nologin oauth2-proxy
sudo install -d -m 750 /etc/oauth2-proxy
sudo chown -R oauth2-proxy:oauth2-proxy /etc/oauth2-proxy
sudo chmod 600 /etc/oauth2-proxy/oauth2-proxy.cfg
sudo systemctl daemon-reload
sudo systemctl enable --now oauth2-proxy
curl -s http://127.0.0.1:4180/ping/ping で OK が出力されれば、プロセスが起動し、設定を読み込んだことを示します。これは oauth2-proxy 自身のヘルスエンドポイントで、セッションは要求しません。応答がない場合は journalctl -u oauth2-proxy -n 50 を確認してください。issuer URL の誤りと長さが不正な cookie secret は、どちらも起動時に失敗し、そのことをログに出力します。
プロバイダーにリダイレクト URI を登録する
プロバイダーで OIDC アプリケーションを作成し、リダイレクト URI に設定ファイルの redirect_url とまったく同じ https://app.example.com/oauth2/callback を指定します。「まったく同じ」とは、スキーム、ホスト、ポート、パスがすべて 1 文字単位で一致するという意味です。末尾のスラッシュがあると、別の URI になります。
これは構成全体で最も多い失敗で、oauth2-proxy が関与する前に発生します。プロバイダーが認可リクエストを拒否して独自のエラーページを表示するため、oauth2-proxy のログには何も記録されません。判断の手掛かりはアドレスバーです。ブラウザーがまだプロバイダーのドメインを表示しており、クエリ文字列に error=invalid_request が含まれているか、ページに redirect_uri が直接表示されています。この場合は、プロキシの設定ではなく、プロバイダー側のアプリケーション登録を修正します。
Issuer URL は手入力せず、プロバイダーからコピーします。oauth2-proxy は oidc_issuer_url に /.well-known/openid-configuration を追加し、起動時にそのディスカバリードキュメントを取得します。まず自分で確認します。
curl -s https://id.example.com/application/o/myapp/.well-known/openid-configuration | head -c 400authorization_endpoint キーを含む JSON が返れば、Issuer URL は正しいです。404 または HTML のエラーページが返る場合は誤っています。oauth2-proxy も同じ 404 で起動に失敗します。まだプロバイダーを選択していない場合は、Keycloak、Authentik、Zitadel の比較で各方式の違いを確認できます。また、Authentik を独自の SSO サーバーとして運用する方法では、この構成におけるプロバイダー側の手順を説明しています。
Nginx: auth_request
Nginx は auth_request によってフォワード認証を実行します。これは内部サブリクエストを発行し、そのステータスコードに応じて処理を分岐します。
# in the http context, next to your other maps
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
server {
listen 443 ssl;
server_name app.example.com;
location /oauth2/ {
proxy_pass http://127.0.0.1:4180;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Auth-Request-Redirect $request_uri;
}
location = /oauth2/auth {
proxy_pass http://127.0.0.1:4180;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-Uri $request_uri;
proxy_set_header Content-Length "";
proxy_pass_request_body off;
}
location / {
auth_request /oauth2/auth;
error_page 401 = @oauth2_signin;
auth_request_set $user $upstream_http_x_auth_request_user;
auth_request_set $email $upstream_http_x_auth_request_email;
proxy_set_header X-User $user;
proxy_set_header X-Email $email;
auth_request_set $auth_cookie $upstream_http_set_cookie;
add_header Set-Cookie $auth_cookie;
proxy_pass http://127.0.0.1:3000;
proxy_set_header Host $host;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
}
location @oauth2_signin {
return 302 /oauth2/sign_in?rd=$scheme://$host$request_uri;
}
}この設定には、重要な点が3つあります。空の Content-Length を指定した proxy_pass_request_body off により、すべての POST のボディがサブリクエストへコピーされなくなります。これは oauth2-proxy がボディを読み取らないため重要です。ファイルをアップロードする場合、デフォルトではファイルが2回送信されます。
auth_request_set $auth_cookie と add_header Set-Cookie の組み合わせにより、更新されたセッション Cookie がブラウザーへ返されます。これを省略すると、nginx はサブリクエストの Set-Cookie を破棄するため、cookie_refresh は何もせずに終了します。ブラウザーはセッションの有効期限が切れるまで古い値を保持します。
error_page 401 = @oauth2_signin により、認証チェックの失敗がログイン処理に変わります。これがないと、未認証の訪問者には何も操作できない 401 Authorization Required ページだけが表示されます。
必ず、再読み込みの前にテストします。
sudo nginx -t && sudo systemctl reload nginx周囲のディレクティブに慣れていない場合は、nginx リバースプロキシ設定の構成で、この設定の下位レイヤーを確認できます。
Traefik: forwardAuth ミドルウェア
Traefik では、同じ処理に 2 つのミドルウェアが必要です。1 つはチェックを実行します。もう 1 つは 401 をブラウザーのリダイレクトに変換します。
# dynamic configuration
http:
middlewares:
oauth-auth:
forwardAuth:
address: https://oauth.example.com/oauth2/auth
trustForwardHeader: true
oauth-errors:
errors:
status:
- "401-403"
service: oauth-backend
query: "/oauth2/sign_in?rd={url}"
statusRewrites:
"401": 302アプリケーションの前段にある router に両方を設定します。また、oauth2-proxy は oauth.example.com で独自の router に公開します。ブラウザーはチェックを経由せずに /oauth2/sign_in と /oauth2/callback にアクセスする必要があるためです。
statusRewrites で 401 を 302 に変換する部分は、見落とされがちです。これがないと、Traefik はサインイン先へのリダイレクトを 401 ステータスで返します。ブラウザーはそのリダイレクトに従わないため、訪問者には Found. という 1 語だけを含むページが表示されます。
trustForwardHeader: true は元のホストと URI を oauth2-proxy に渡します。oauth2-proxy は、それらを使って、ユーザーが要求したページへ戻す rd の値を組み立てます。そのホストも対象に含めるよう whitelist_domains を設定してください。設定しないと、oauth2-proxy はオープンリダイレクトのリスクを避けるため rd パラメーターを削除します。その結果、ログイン後に全員が / に移動します。通常、Traefik のサーバーは複数のアプリケーションを同時に前段で処理します。複数の Docker Compose アプリケーションを 1 つの Traefik インスタンスでルーティングする方法では、この構成に接続できる router の構成を説明しています。
Caddy: forward_auth
app.example.com {
handle /oauth2/* {
reverse_proxy oauth2-proxy.internal:4180 {
header_up X-Real-IP {remote_host}
header_up X-Forwarded-Uri {uri}
}
}
handle {
forward_auth oauth2-proxy.internal:4180 {
uri /oauth2/auth
header_up X-Real-IP {remote_host}
copy_headers X-Auth-Request-User X-Auth-Request-Email
@error status 401
handle_response @error {
redir * /oauth2/sign_in?rd={scheme}://{host}{uri}
}
}
reverse_proxy upstream.internal:3000
}
}ここでは順序が重要です。/oauth2/* ブロックを先に置き、forward_auth は指定しません。未ログインの訪問者がサインインパスとコールバックパスに到達する必要があるためです。これらのパスより前にチェックを置くと、ブラウザーが諦めるまでログインリダイレクトが自分自身を繰り返します。
copy_headers により、認証済みの識別情報が upstream リクエストに引き継がれます。ただし、oauth2-proxy が set_xauthrequest = true で実行されている場合に限り、値が生成されます。どのプロキシを選ぶかは別の問題であり、nginx、Caddy、Traefik の比較で詳しく扱っています。
ログインするとログインページに戻るのはなぜですか?
プロバイダーでサインインすると、プロバイダーはブラウザーを戻します。その後、oauth2-proxy はすぐにブラウザーを再びプロバイダーへリダイレクトします。このループは、コールバックリクエストが、oauth2-proxy がリダイレクト前に設定した Cookie なしで到着したことを示します。ログには次のように記録されます。
No cookies were found in OAuth callback.別の Cookie は送信されたものの、正しい Cookie が送信されなかった場合は、次のように記録されます。
Cookies were found in OAuth callback, but none was a CSRF cookie.CSRF は cross-site request forgery を意味します。この Cookie は、コールバックを、そのコールバックを開始したログイン処理と関連付けるために使用されます。ブラウザーでは、同じ問題が次のように表示されます。
Login Failed: Unable to find a valid CSRF token. Please try again.次の4つの原因を、この順番で確認してください。
cookie_secure = trueが設定されている状態で、ブラウザーが平文の HTTP でサイトにアクセスしている。ブラウザーはhttp://origin ではSecureとしてマークされた Cookie を保存しないため、その Cookie が送り返されることはありません。TLS (transport layer security) を正しく終端するか、localhost でのテスト中だけcookie_secure = falseを設定してください。- アドレスバーのホスト名を対象に含まない
cookie_domainsの値。.example.comはapp.example.comを対象にしますが、app.example.netにはまったく作用しません。 - ブラウザーが Cookie を破棄している。厳格なプライバシー拡張機能やサードパーティー Cookie のブロックにより、リダイレクト開始後からコールバックまでの間に
_oauth2_proxy_csrfが削除されることがあります。 - クロックのずれ。サーバーの時刻がプロバイダーの時刻から大きくずれていると、ID token の
iatとexpが許容範囲外になり、セッションは到着時に拒否されます。timedatectlでSystem clock synchronized: yesを確認できるはずです。
推測せず、サーバー側から動作を確認します。
sudo journalctl -u oauth2-proxy -fprivate window でアプリを開きます。すべてのリクエストがステータス付きでログに記録されるため、コールバック直後にプロバイダーへのリダイレクトが再び発生していれば、それがループであることをログ上で確認できます。
ログインをスキップする必要があるパス: API、webhook、websocket
Forward auth は、cookie を保持するブラウザーを前提とします。ブラウザーを使わない呼び出し元では問題が起きます。
Authorization: Bearer <token> を送信する API クライアントには cookie がありません。そのため、プロバイダーのログインページへの 302 を受け取り、その後 HTML を JSON として解析しようとします。対処方法は2つあります。skip_jwt_bearer_tokens = true を設定すると、oauth2-proxy は同じ issuer が発行した有効な JWT(JSON web token)bearer token を受け入れます。API クライアントがすでにプロバイダーから token を取得している場合に適しています。それ以外の場合は、パスを除外します。
skip_auth_routes = [
"^/api/",
"POST=^/webhook/",
"GET=^/healthz$"
]各値は正規化されたパスに対して照合する正規表現です。必要に応じて、HTTP method と = を先頭に付けます。POST=^/webhook/ により、webhook receiver は POST を受け付けたまま、同じパスにブラウザーでアクセスしたユーザーにはログインを要求できます。各エントリは認証ゲートに開ける穴です。そのため、正規表現は ^ でアンカーし、呼び出し元が許容する範囲でできるだけ限定してください。
websocket は誤解されやすいケースです。upgrade request は、他の request と同じ cookie を含む通常の HTTP GET です。そのため通常どおりチェックを通過し、除外は必要ありません。問題になるのは、その前後のプロキシ処理です。保護対象の location に Upgrade と Connection の header がないと、upgrade は完了しません。アプリの client はブラウザーの console に WebSocket connection ... failed message を表示しながら、いつまでも再試行します。パスを除外しても、request はすでに認証済みなので、この問題は解決しません。
実際の制限も1つあります。チェックは upgrade 時に1回だけ実行されます。数時間開いたままの websocket は再チェックされません。そのため、プロバイダーでユーザーを削除しても、すでに保持されている socket は閉じません。稼働中の接続を切断するには、アプリを再起動してください。
セッションストレージと大きくなりすぎる Cookie
デフォルトでは、セッション全体が cookie_secret で暗号化され、Cookie 内に保存されます。これにより oauth2-proxy はステートレスで動作し、追加のサービスも必要ありません。ただし、ブラウザーが Cookie のサイズを約 4 KB に制限するため、上限があります。ID token に多数の group claim が含まれている場合、oauth2-proxy はセッションを _oauth2_proxy_0、_oauth2_proxy_1 以降に分割します。分割数が数個を超えるとリクエストヘッダーが大きくなり、アプリがリクエストを受け取る前に nginx が 400 Request Header Or Cookie Too Large を返すことがあります。
この場合は、セッションをサーバー側に移します。
session_store_type = "redis"
redis_connection_url = "redis://127.0.0.1:6379"ブラウザーには短い ticket だけが保持され、暗号化されたセッションは Redis に保存されます。その代わり、Redis を稼働させ続ける必要があります。Redis が停止すると、すべてのセッションが無効になり、全員が同時にログアウトされます。Cookie ストアにも固有の問題があります。同じセッションを更新する2つのリクエストが同時に処理されると競合し、再ログインが必要になることがあります。
Forward auth で得られないもの
これは入口に設けるゲートです。アプリケーション内部の認可ではありません。この違いによって、この方式が適しているかどうかが決まります。
ユーザーが通過すると、アプリケーションから見える情報は従来と変わりません。アプリに独自のロールがあっても、forward auth がそれを設定するわけではありません。ただし、アプリがヘッダーによる認証に対応し、ヘッダーをアカウントにマッピングする場合は別です。Grafana は auth.proxy 設定によってこれに対応しています。多くの self-hosted アプリは対応していないため、ゲートを通過したユーザーは全員、アプリケーションからは同じ単一の ID に見えます。その ID が admin であることも少なくありません。
アプリケーション独自の API トークンも保護されません。アプリが発行した personal access token は oauth2-proxy ではなくアプリケーションに対して認証するため、ゲートを前段に置いた時点でそのトークンは機能しなくなります。API パスを除外して利用可能に戻すと、そのパスを守るものはトークンだけになります。これで、1 つのサービス上に2つの認証方式を運用することになり、SSO が適用されるのは一方だけです。
3つ目の不足点は、失効処理です。プロバイダーでユーザーを削除すると、新しいログインは停止し、cookie_refresh が実行するトークン更新も停止します。しかし、既存のセッション Cookie は期限が切れるまで有効です。cookie_expire のデフォルトは 168 hours であるため、削除したユーザーに1週間のアクセスを許すことになります。cookie_refresh を hour などの短い期間に設定し、失効がその時間内に反映されるようにしてください。
監査証跡もゲートで止まります。oauth2-proxy は誰がいつ通過したかを記録します。一方、アプリケーションに残るのは、名前のないセッションのログです。誰が設定を変更したのかを確認する必要がある場合、アプリケーションでヘッダーの ID を記録することが最低限必要です。正確な答えは、ユーザーごとの実アカウントを用意することです。
SSO の費用を負担する方が適切な場合
アプリにログイン機能がまったくない場合や、共有パスワードしかない場合に、利用者の追加と削除を一元管理したいなら、Forward auth が適しています。導入には半日と追加のプロセス1つが必要ですが、HTTP に対応するアプリであれば利用できます。
同じアプリ内で利用者ごとに異なる権限が必要な場合、Forward auth は適していません。認証ゲートだけでは、「Ana はダッシュボードを編集でき、Bo は閲覧だけできる」という条件を表現できません。ベンダーが SSO tier を提供している場合、実際に購入する価値があるのは通常、グループとロールのマッピングです。これをヘッダーとプロキシルールで再構築すると、料金を支払うよりも壊れやすい構成になります。どちらを選ぶか決める前に、SSO tier の料金体系を確認してください。
ほかにも、同じ判断になる状況が2つあります。アプリケーション内で利用者ごとの監査記録が必要なコンプライアンス対応では、プロキシのアクセスログを証拠として認められません。また、ブラウザー Cookie を保持しないモバイルまたはデスクトップクライアントを備えたアプリでは、すべてのリクエストで認証ゲートとの競合が発生します。
FAQ
Forward auth とは何ですか?
Forward auth は、リバースプロキシが受信したすべてのリクエストを上流へ渡す前に、別の認証サービスへ確認する方式です。プロキシはリクエストヘッダーを /oauth2/auth などのエンドポイントへ送信し、ステータスコードを確認します。202 は許可を示すため、元のリクエストはアプリケーションへ転送されます。401 はセッションがないことを示すため、プロキシはブラウザーをログインページへリダイレクトします。Nginx では auth_request ディレクティブ、Traefik では forwardAuth ミドルウェア、Caddy では forward_auth を使用して実装します。
oauth2-proxy がログインページへ繰り返しリダイレクトするのはなぜですか?
CSRF cookie が付いていない状態でコールバックリクエストが oauth2-proxy に到達したため、oauth2-proxy が認証フローを最初からやり直しています。サーバーログには No cookies were found in OAuth callback. と表示され、ブラウザーには Login Failed: Unable to find a valid CSRF token. Please try again. と表示されます。通常の原因は、ブラウザーが HTTP でアクセスしたサイトで cookie_secure = true が設定されていることです。ブラウザーは http:// origin では Secure cookie を保存しないためです。次に多い原因は、アドレスバーに表示されているホスト名を cookie_domains の値がカバーしていないことです。
API クライアントまたは webhook を oauth2-proxy 経由で通すにはどうすればよいですか?
skip_auth_routes にアンカー付きの正規表現を指定します。必要に応じて、1 つの HTTP メソッドだけに適用できます。例: POST=^/webhook/。API クライアントが同じプロバイダーによって発行された JWT をすでに保持している場合は、skip_jwt_bearer_tokens = true により cookie の代わりにそのトークンを受け入れ、パスの保護を維持できます。skip_auth_routes に記載した内容はすべてのユーザーに対して認証なしになるため、各式は呼び出し元に必要な範囲まで狭くしてください。
oauth2-proxy はアプリケーションにユーザーごとの権限を渡しますか?
いいえ。oauth2-proxy は認証のゲートであり、認可システムではありません。誰がアプリケーションへ到達できるかを判断します。アプリケーションが identity header を読み取り、アカウントに対応付けない限り、到達したユーザーはアプリケーションから同じように見えます。Grafana では auth.proxy 設定を使用してこれを実行できます。多くの self-hosted アプリケーションは対応していないため、ゲートを通過した全員が、アプリケーションの実行に使用されている 1 つの identity を共有します。
identity header を自分で設定して oauth2-proxy を回避できますか?
はい。アプリケーションへ直接到達できる場合は可能です。identity は X-Auth-Request-Email のような平文のヘッダーで渡され、アプリケーションは受信した値をそのまま信頼します。アプリケーションのポートへ接続できる人は誰でも、そのヘッダーを送信して任意のユーザーになれます。アプリケーションを 127.0.0.1 に bind するか、公開ポートのない内部 Docker network 上で実行してください。sudo ss -tlnp で設定を確認します。