Cloudflare Accessで通した認証結果を取得してみる
こんばんは、情報システム室の夏目です。
個人的なWebアプリなどでCloudflare Accessでアクセス制限をかけているのですが、認証結果を取得できるようなので調べてみました。
Cloudflare Access
Cloudflare Access sits in front of your applications and checks every request against your Access policies before letting users through. It supports several application types, each designed for a different use case. Your choice depends on where your application is hosted, how users connect to it, and what level of control you need over sessions and authorization.
Cloudflare Accessはアプリケーションの前面に配置され、ユーザーのアクセス要求を許可する前に、すべてをAccessポリシーと照合して検証します。複数のアプリケーションタイプをサポートしており、それぞれが異なるユースケース向けに設計されています。適切な選択を行うには、アプリケーションのホスティング環境、ユーザーの接続方法、およびセッション管理や認証制御の必要レベルを考慮する必要があります。
Cloudflare Zero Trustの1機能で、簡単にアプリケーションに対する認証とアクセス制限をかけることができます。
アプリケーションは4種類あります。
- Self-hosted application
- トラフィックの行き先を自分で管理しているリソース全般 (公開WebサイトやWorkerなど)に対するアクセス制限を行います
- 最も汎用性が高く、よく使われています
- この記事もSelf-hosted applicationの前提で話をします
- SaaS application
- SalesforceやSlackなど組織がホストしていないサードパーティツール向けです
- SSOの設定を行うときに、SaaSプロバイダーだけでは設定できない条件を設定する場合に使います
- Infrastructure application
- サーバーやインフラターゲットに対して、プロトコルまで考慮したアクセス制限を行います
- Self-hosted applicationでは到達できるかという点で見ますが、Infrastructure applicationでは接続後に何ができるかまでを制限できます
- Bookmark
- Cloudflare AccessのApp Launcher上に並べて表示したい任意のURLへのリンク
- App Launcherに表示するかだけの制御しかできません
- Cloudflareと統合していない外部ツールも含め、ユーザーが使うツールを1つのポータルにまとめる目的で使います
Self-hosted applicaion
これについてはもう少しだけ詳しく説明します。
Self-hosted applicationには用途別に3パターンあります。
- Public hostname
- CloudflareでDNSを管理しているWebアプリの手前にCloudflare Accessを置きます
- Cloudflareがリクエストをプロキシしてログイン画面を提示しアクセス制限を行います
- Workers保護
- Public hostnameと同様のアクセス制限をWorkerに設定します
- Private network
- プライベートIP/ホスト名/CIDR範囲 とポート範囲を指定してアクセス制限をします
- Cloudflare One Client (旧WARP)が必須で、ユーザー端末からCloudflare Tunnelなどでネットワークを接続する必要がある
Public hostnameを使うことが多いと思います。
この記事ではPublic hostname前提で話をします。
(おそらくWorkers保護も同様に動くとは思います)
基本的には User -> Cloudflare Access -> Webアプリ (オリジン) という形で、Cloudflare Accessがリバースプロキシのように動いて、Webアプリへのアクセス制限を挟んでくれます。
認証を通した後WebアプリにCloudflare Accessがオリジンにリクエストを投げるとき、通した認証の情報を付与してWebアプリにリクエストを投げるので、それについて調べてみました。
Cloudflare Accessが付与する認証情報
Cloudflare Accessがオリジンにリクエストを投げるとき、3つのヘッダーを追加します。
cf-access-authenticated-user-email- 認証を通したユーザーのメールアドレス
cf-access-jwt-assertion- Cloudflare Accessが発行するJWTトークン
cookieCF_AppSessionとCF_Authorizationの二つのキーがCookieに追加されますCF_Authorizationの値はcf-access-jwt-assertionヘッダーと同じ値です
この3つのヘッダーが追加されたリクエストがオリジンに届くのでオリジンで認証情報を取得することができます。
HTTPのヘッダーに追加されるので、静的Webサイトの場合はフロント側でCookieを使うことになります。
cf-access-jwt-assertion
JWTのペイロードは以下のようになっています。
{
"aud": [
"0000000000000000000000000000000000000000000000000000000000000000"
],
"email": "xxxxxxxxxxx@gmail.com",
"exp": 1787034504,
"iat": 1786948104,
"nbf": 1786948104,
"iss": "https://luciferous.cloudflareaccess.com",
"type": "app",
"identity_nonce": "TRwu3dV9jks0VBDA",
"sub": "1e69e9c9-e86d-4740-b58c-f18cf44426f5",
"device_id": "38f1faa5-0b15-4ea1-bc86-766693fd6041",
"h_INTERNAL_DO_NOT_USE": "trial-access-cert-header.luciferous.app",
"country": "JP",
"policy_id": "ef81d4fd-560f-413b-9801-d8158a047fe0"
}
aud- Cloudflare Accessのアプリケーション毎に固有の値を持ちます
- 確認方法は次のURLで解説されています
email- 認証を通した人のメールアドレスです
sub- JWTの発行者として、Cloudflare Zero TrustのチームドメインのURLが入ります
.well-known/openid-configurationにアクセスすると、jwks_uriとissだけが見えました
policy_id- Cloudflare Accessのアプリケーションに設定しているPolicyのIDです
- このPolicyでどういった認証を行うのかを設定しています
- Cloudflare Accessのアプリケーションに設定しているPolicyのIDです
特に大きな意味がありそうなclaimは上記の4つでしょうか。
.well-known/openid-configuration に jwks_uri と iss があるので、JWTによる認証を組み込むのは簡単そうです。
Cookieについて

Cloudflare Accessのオリジンがアプリケーションサーバーではなく単純なWebサーバーである場合 (Cloudflare PagesとかCloudflare Workerのstatic assetとか) はヘッダーの値を取得できません。
そのためJWTが欲しければCookieから取得する必要があります。
(Cloudflare Accessのアプリケーションの設定でHttpOnlyになっていない必要はありますが)
Cookieの CF_Authorization については、上記HttpOnlyのように、Cloudflare Accessのアプリケーションで設定できる項目があります。

Httpのみ- CookieのHttpOnly属性を有効にするかを選択できます
- 別ホストへのリクエストをウェブフロントから直接行うときJWTを使うにはオフにする必要があります
バインド Cookie を有効にする- これをオンにすると、Cookieに
CF_Bindingというキーが追加で発行されるようになります CF_Bindingの値はCF_Authorizationと組になっており、 この組が一致する場合のみCloudflare Accessはオリジンへのリクエストを通してくれる- 不一致などの場合はCloudflare Access側でリクエストが止められる
- オリジンへのリクエストからは
CF_Bindingの値は削除される
- これをオンにすると、Cookieに
Cookie パス属性を強制する- オンにするとCookieのPath属性が付与されるようになります
- アプリケーションにAccessの対象のホスト名を設定するとき、パスも指定できるのでそのパスがPath属性の値になる
- オンにするとCookieのPath属性が付与されるようになります
- 先行リダイレクト Cookie
- アプリケーションに複数のホスト名がある場合、オンにしていると各ホスト用のCookieを一括で設定してくれる
- そのためホストを移動する際に再度サインインしなくてよくなる
- 同じサイト属性
- CookieのSameSite属性
/cdn-cgi/access/get-identity
Cloudflare Accessでアクセス制限したWebフロントからJWTではなく、認証情報だけを取得する方法もあります。
async function getIdentity() {
const resp = await fetch("/cdn-cgi/access/get-identity", { credentials: "include" })
console.log(await resp.json());
}
{
"id": "000000000000000000000",
"name": "Yuta Natsume (sinofseven)",
"email": "xxxxxxxxxxx@gmail.com",
"idp": {
"id": "98caf51f-8c8b-4c16-a4ca-3c8f904249c5",
"type": "google"
},
"geo": {
"country": "JP"
},
"user_uuid": "4ca3736b-9b0f-4db4-baf3-6a7616b90582",
"account_id": "00000000000000000000000000000000",
"iat": 1786932792,
"devicePosture": {},
"ip": "2001:db8:1234:5678::1",
"auth_status": "NONE",
"common_name": "",
"service_token_status": false,
"is_warp": true,
"is_gateway": true,
"gateway_account_id": "00000000000000000000000000000000",
"device_id": "c17a098b-c3ee-4d82-9498-70466269c1d4",
"version": 0,
"device_sessions": {
"6903ebcd-34c2-41ba-a402-1c03091fc9a8": {
"last_authenticated": 1786932792
},
"a7524542-c62a-4a71-87fb-9a4fdf56c557": {
"last_authenticated": 1785822704
}
}
}
/cdn-cgi/access/get-identity に Cookieとして CF_Authorization を含めてリクエストを投げると取得できます。
Fetch APIで {credentials: "include"} としてリクエストを投げるだけなので、Cookieの設定でHttpOnly属性となっていても取得できます。
まとめ
以上、Cloudflare Accessで通した認証情報を取得してみた話でした。
何かのお役に立てたら幸いです。




