← Back to knowledge base
medium

Troubleshooting policy-based firewall authentication with auth-on-demand set to always

Confirmed 9/19/2026

Problem

When policy-based firewall authentication is enabled and `auth-on-demand` is set to `always`, FortiGate gives authentication policies precedence over IP-based policies. Administrators may need to determine where policy evaluation stops, whether the authentication portal redirect occurs, and which policy is selected after login.

Symptoms

Unauthenticated traffic matches an initial policy but is stopped for an identity check and redirected to the authentication portal. After successful authentication, FortiGate evaluates the policies again and should select the policy associated with the authenticated user group. Incorrect policy order or source-subnet definitions can cause traffic to bypass the intended authentication prompt.

Environment

FortiGate using policy-based firewall authentication. In the documented test, policy 3 contains a local user group and is used to trigger the authentication portal. The user `kraken` belongs to `LDAP_Group`, and policy 6 is configured for `LDAP_Group`.

Root Cause

The setting `set auth-on-demand always` forces on-demand firewall authentication and makes an authentication policy take precedence over an IP policy. Policy sequence remains significant: a subnet can avoid the portal if a matching exemption or IP policy is ordered above the firewall authentication policy. Source-address scope can also affect which clients are prompted.

Solution

  1. Configure FortiGate to trigger firewall authentication on demand:
config user setting
    set auth-on-demand always
end
  1. Start a flow debug filtered by the source and destination addresses. Replace x.x.x.x and y.y.y.y with the addresses being tested:
diagnose debug flow filter saddr x.x.x.x
diagnose debug flow filter daddr y.y.y.y
diagnose debug flow show function-name enable
diagnose debug flow show iprope enable
diagnose debug flow trace start 99
diagnose debug enable
  1. Generate traffic from the affected client and review the unauthenticated flow. The following sample shows traffic matching policy 3, stopping at the identity check, and being redirected to the authentication portal:
id=20085 trace_id=1000 func=print_pkt_detail line=5863 msg="vd-root:0 received a packet(proto=6, 10.234.1.225:50281->172.217.26.68:443) tun_id=0.0.0.0 from port2. flag [S], seq 4065843363, ack 0, win 8192"
id=20085 trace_id=1000 func=init_ip_session_common line=6042 msg="allocate a new session-00093fac, tun_id=0.0.0.0"
id=20085 trace_id=1000 func=iprope_dnat_check line=5305 msg="in-[port2], out-[]"
id=20085 trace_id=1000 func=iprope_dnat_tree_check line=830 msg="len=0"
id=20085 trace_id=1000 func=iprope_dnat_check line=5317 msg="result: skb_flags-02000000, vid-0, ret-no-match, act-accept, flag-00000000"
id=20085 trace_id=1000 func=vf_ip_route_input_common line=2605 msg="find a route: flag=04000000 gw-10.47.15.254 via port1"
id=20085 trace_id=1000 func=iprope_fwd_check line=789 msg="in-[port2], out-[port1], skb_flags-02000000, vid-0, app_id: 0, url_cat_id: 0"
id=20085 trace_id=1000 func=__iprope_tree_check line=549 msg="gnum-100004, use svc hash, slot=27, len=6"
id=20085 trace_id=1000 func=__iprope_check_one_policy line=2029 msg="checked gnum-100004 policy-3, ret-matched, act-accept"
id=20085 trace_id=1000 func=get_new_addr line=1228 msg="find SNAT: IP-10.47.1.175(from IPPOOL), port-50281"
id=20085 trace_id=1000 func=__iprope_user_identity_check line=1818 msg="ret-stop"
id=20085 trace_id=1000 func=iprope_fwd_check line=826 msg="after iprope_captive_check(): is_captive-0, ret-stop, act-drop, idx-0"
id=20085 trace_id=1000 func=iprope_fwd_auth_check line=845 msg="after iprope_captive_check(): is_captive-0, ret-stop, act-drop, idx-0"
id=20085 trace_id=1000 func=__iprope_check line=2276 msg="gnum-3, check-ffffffffa002be00"
id=20085 trace_id=1000 func=__iprope_check_one_policy line=2029 msg="checked gnum-3 policy-4294967295, ret-no-match,act-drop"
id=20085 trace_id=1000 func=__iprope_check_one_policy line=2029 msg="checked gnum-3 policy-4294967295, ret-no-match,act-drop"
id=20085 trace_id=1000 func=__iprope_check_one_policy line=2029 msg="checked gnum-3 policy-4294967295, ret-no-match,act-drop"
id=20085 trace_id=1000 func=__iprope_check_one_policy line=2029 msg="checked gnum-3 policy-4294967295, ret-no-match,act-drop"
id=20085 trace_id=1000 func=__iprope_check_one_policy line=2029 msg="checked gnum-3 policy-4294967295, ret-no-match,act-drop"
id=20085 trace_id=1000 func=__iprope_check_one_policy line=2029 msg="checked gnum-3 policy-4294967295, ret-matched, act-drop"
id=20085 trace_id=1000 func=__iprope_check_one_policy line=2246 msg="policy-4294967295 is matched, act-redirect"
id=20085 trace_id=1000 func=__iprope_check line=2293 msg="gnum-3 check result: ret-matched, act-redirect, flag-00000020, flag2-00000000"
id=20085 trace_id=1000 func=iprope_policy_group_check line=4734 msg="after check: ret-matched, act-redirect, flag-00000020, flag2-00000000"
id=20085 trace_id=1000 func=iprope_fwd_auth_check line=874 msg="iprope_auth_portal_check() result: ret-matched, act-redirect"
id=20085 trace_id=1000 func=av_receive line=433 msg="send to application layer"
  1. Identify where policy processing stops. In this example, FortiGate first accepts policy 3 and then returns ret-stop during the user identity check:
id=20085 trace_id=1000 func=__iprope_check_one_policy line=2029 msg="checked gnum-100004 policy-3, ret-matched, act-accept"
id=20085 trace_id=1000 func=__iprope_user_identity_check line=1818 msg="ret-stop"
  1. Confirm that the debug includes act-redirect. This indicates that the authentication portal should be presented. The portal uses the FortiGate interface IP with port 1000 for HTTP or port 1003 for HTTPS. Example HTTP URL:

http://10.234.1.175:1000/

  1. Authenticate with the appropriate account. In the documented test, the username is kraken, which belongs to LDAP_Group.

  2. Generate traffic again after login. FortiGate reevaluates the policy list. The following sample shows policy 3 failing the identity match, policy 6 matching LDAP_Group, and the traffic being accepted with SNAT:

id=20085 trace_id=6552 func=print_pkt_detail line=5863 msg="vd-root:0 received a packet(proto=6, 10.234.1.225:50760->104.16.148.64:443) tun_id=0.0.0.0 from port2. flag [S], seq 3574129298, ack 0, win 8192"
id=20085 trace_id=6552 func=init_ip_session_common line=6042 msg="allocate a new session-00095bca, tun_id=0.0.0.0"
id=20085 trace_id=6552 func=iprope_dnat_check line=5305 msg="in-[port2], out-[]"
id=20085 trace_id=6552 func=iprope_dnat_tree_check line=830 msg="len=0"
id=20085 trace_id=6552 func=iprope_dnat_check line=5317 msg="result: skb_flags-02000000, vid-0, ret-no-match, act-accept, flag-00000000"
id=20085 trace_id=6552 func=vf_ip_route_input_common line=2605 msg="find a route: flag=04000000 gw-10.47.15.254 via port1"
id=20085 trace_id=6552 func=iprope_fwd_check line=789 msg="in-[port2], out-[port1], skb_flags-02000000, vid-0, app_id: 0, url_cat_id: 0"
id=20085 trace_id=6552 func=__iprope_tree_check line=549 msg="gnum-100004, use svc hash, slot=27, len=5"
id=20085 trace_id=6552 func=__iprope_check_one_policy line=2029 msg="checked gnum-100004 policy-3, ret-matched, act-accept"
id=20085 trace_id=6552 func=__iprope_user_identity_check line=1818 msg="ret-no-match"
id=20085 trace_id=6552 func=__iprope_check_one_policy line=2029 msg="checked gnum-100004 policy-6, ret-matched, act-accept"
id=20085 trace_id=6552 func=__iprope_user_identity_check line=1818 msg="ret-matched"
id=20085 trace_id=6552 func=__iprope_check line=2276 msg="gnum-4e20, check-ffffffffa002be00"
id=20085 trace_id=6552 func=__iprope_check_one_policy line=2029 msg="checked gnum-4e20 policy-6, ret-no-match, act-accept"
id=20085 trace_id=6552 func=__iprope_check_one_policy line=2029 msg="checked gnum-4e20 policy-6, ret-no-match, act-accept"
id=20085 trace_id=6552 func=__iprope_check_one_policy line=2029 msg="checked gnum-4e20 policy-6, ret-no-match, act-accept"
id=20085 trace_id=6552 func=__iprope_check line=2293 msg="gnum-4e20 check result: ret-no-match, act-accept, flag-00000000, flag2-00000000"
id=20085 trace_id=6552 func=get_new_addr line=1228 msg="find SNAT: IP-10.47.1.175(from IPPOOL), port-50760"
id=20085 trace_id=6552 func=__iprope_check_one_policy line=2246 msg="policy-6 is matched, act-accept"
id=20085 trace_id=6552 func=iprope_fwd_check line=826 msg="after iprope_captive_check(): is_captive-0, ret-matched, act-accept, idx-6"
id=20085 trace_id=6552 func=iprope_fwd_auth_check line=845 msg="after iprope_captive_check(): is_captive-0, ret-matched, act-accept, idx-6"
id=20085 trace_id=6552 func=iprope_reverse_dnat_check line=1307 msg="in-[port2], out-[port1], skb_flags-02000000, vid-0"
id=20085 trace_id=6552 func=iprope_reverse_dnat_tree_check line=923 msg="len=0"
id=20085 trace_id=6552 func=fw_forward_handler line=879 msg="Allowed by Policy-6: SNAT"
id=20085 trace_id=6552 func=__ip_session_run_tuple line=3490 msg="SNAT 10.234.1.225->10.47.1.175:50760"
  1. Review firewall-policy order and source addressing before deployment. Policy 3 is intended to prompt for authentication through its local user group; after login, the firewall checks the policies again to find the permitted user-group policy. If a particular subnet must be exempt from the authentication prompt, move its policy above the firewall authentication policy. Alternatively, define the source IP or subnet that must use policy-based firewall authentication. Carefully plan policy sequence and subnet scope before enabling auth-on-demand always.

Verification

Before login, verify that the flow shows policy 3 with ret-matched, act-accept, followed by the identity result ret-stop and the portal result act-redirect. Confirm that the portal is reachable through the interface IP on HTTP port 1000 or HTTPS port 1003. After login, verify that policy evaluation runs again, policy 6 reports an identity ret-matched, and the final flow contains policy-6 is matched, act-accept and Allowed by Policy-6: SNAT.

Tags

No tags yet.

Community rating

— / 5 (0)

Discussion (0)

    No comments yet.