Cloudflare Access: ログイン・拒否・CLI 承認ページを HTML と Liquid で作り込む
Access のログイン、ID 拒否、Forbidden、コマンドライン承認の 4 種類のページを、HTML + Liquid テンプレートでアプリごとに差し替えられるようになった(2026-10-27)。
社内ツールを Access で守ると、拒否されたユーザーは素っ気ない既定ページを見て「なぜ入れないのか」を管理者に聞きに来る。テンプレートにアプリ名、サインイン中のメール、Ray ID などを差し込めば、問い合わせ先や必要な申請手順をその場で案内できる。
ページの種類と必須要素
| 種類 | 使う場面 | 必須要素 |
|---|---|---|
| Login | アプリへのサインイン | <cf-access-authbox></cf-access-authbox> をちょうど 1 つ |
| Identity denied | サインイン後にポリシーで拒否 | なし |
| Forbidden | サービストークン認証の失敗など、ID 以外の理由で拒否 | なし |
| Interstitial | CLI(cloudflared access login など)のログイン要求を承認・拒否 | <cf-access-cli-approval></cf-access-cli-approval> をちょうど 1 つ |
必須要素の中に Access が本物のサインインフォームや承認ボタンを差し込む。Liquid の if やループの中に入れず、描画結果で必ず 1 回だけ出るようにする。
手順
- Cloudflare One ダッシュボードの Reusable components > Custom pages で Access custom pages の Manage を開き、Create custom page で名前と種類を選ぶ(種類ごとのひな形が入る)。
- HTML と Liquid を編集し、Variables で使える変数を、Problems で検証エラーを確認して Publish。
- Access controls > Applications で対象アプリの Additional settings > Custom block pages から、種類に合うテンプレートを選んで保存する。一覧の Set as default でアカウント既定にもできる(アプリ個別の指定が優先)。
拒否ページの例
html
<h1>アクセスできません</h1>
<p>{{ app.name }} へのアクセス権がありません。</p>
{% if user.email %}
<p>{{ user.email }} でサインインしています。別アカウントなら一度ログアウトしてください。</p>
{% endif %}
{% if ray_id %}
<p>管理者に連絡するときはこの ID を伝えてください: {{ ray_id }}</p>
{% endif %}使える変数はページの種類で違う。Login なら app_name、app_domain、idps、message など、拒否ページなら app、任意の user・ray_id・policy_evaluation、Interstitial なら app・requesting_tool など。任意の値は {% if %} で囲む(ない変数は空文字になる)。Login では message.text を必ず表示しておくと、サインイン失敗の理由が利用者に伝わる。
注意点
- 見た目を変えるだけで、アクセス可否の判定は変わらない。テンプレートが壊れていれば既定ページにフォールバックする。
- 独自の JavaScript、インラインイベントハンドラ、自前のログインフォームは使えない。Liquid の
include/render/layout/echo/rawも不可。外部の画像・フォントは CSP に従い HTTPS で読む。 - 編集画面の検証は描画プレビューではない。共有テンプレートを直すと割り当て済みの全アプリに反映されるので、テスト用アプリに割り当てて実際のフローで確認してから広げる。
policy_evaluationをそのまま出すとグループ名やポリシーの中身が漏れる。見せる項目は選ぶ。- エディタにダウンロード機能はないので、HTML はリポジトリなどダッシュボードの外にも保管しておく。
出典
- @CFchangelog · 2026-10-29
- Cloudflare Docs「Access custom pages」 developers.cloudflare.com