By Manny Fernandez

August 24, 2026

Deploying SCIM Clients on FortiOS: Automated User and Group Provisioning for SAML-Backed Access

Objective: This guide shows you how to turn a FortiGate into a SCIM 2.0 service endpoint so that an external identity provider can push users and groups into FortiOS before anyone ever logs in, then bind that provisioned directory to a SAML single sign-on object so firewall policies, SSL VPN portals, and proxy policies can match on real group membership. The result is an identity-aware edge that knows who exists, who belongs to what, and who was just terminated, without a single LDAP bind or FSSO collector agent.

Target Audience: Network Security Engineers, Identity and Access Management engineers, Systems Engineers, and anyone responsible for FortiGate authentication design in an enterprise or MSSP environment.

1. Executive Summary

SAML solved authentication on the FortiGate. It did not solve identity. With SAML alone, the FortiGate learns nothing about a user until that user authenticates, and it learns only what the assertion happens to carry at that moment. You cannot build a firewall policy around a group that the FortiGate has never heard of, you cannot see a user in the Firewall Users monitor before their first login, and when HR disables an account on Tuesday afternoon, the FortiGate has no idea anything changed.

SCIM, the System for Cross-domain Identity Management defined in RFC 7643 and RFC 7644, closes that gap. It is a REST and JSON protocol for pushing identity lifecycle events, create, update, and delete, from an identity source to a downstream application. FortiOS 7.6.0 added SCIM server support, and 7.6.1 added the GUI for managing SCIM client entries. The feature carries forward into FortiOS 8.0.

The naming trips people up on day one, so get it straight before you touch a CLI prompt:

Term Who plays it What it does
SCIM server (service provider) The FortiGate Listens on an HTTP or HTTPS port, exposes the /scim/v2 resource tree, and stores the users and groups it is handed.
SCIM client (identity source) FortiAuthenticator, Entra ID, Okta Authenticates to the FortiGate and issues POST, PATCH, PUT, and DELETE calls to keep the directory in sync.
config user scim FortiOS CLI table One entry per identity source that is allowed to provision into this VDOM. This is the object the GUI calls a SCIM Client.

Read that table twice. The object you create on the FortiGate is called a SCIM Client, but the FortiGate itself is the SCIM server. You are defining who is allowed to talk to you, not where you go to fetch data. Nothing in this feature polls anything. It is entirely push-driven.

2. Prerequisites & Architecture

2.1 Assumed Knowledge

  • Comfortable in the FortiOS CLI, including config tree navigation, show full-configuration, and diagnose commands.
  • Working understanding of SAML 2.0 roles: identity provider, service provider, assertion, and attribute statements.
  • FortiOS certificate handling, specifically the difference between config certificate local, config certificate ca, and config certificate remote.
  • Basic REST concepts. You will not write any code, but knowing what a 401 versus a 403 versus a 409 means will save you an hour.
  • Familiarity with firewall user groups and the difference between a local group, a Fortinet Single Sign-On group, and a remote-server group match.

2.2 Environment and Lab Requirements

  • FortiGate running FortiOS 7.6.1 or later. 7.6.0 has the underlying SCIM server but no GUI. 7.6.2 renamed two CLI attributes, which matters if you automate. Anything built on 7.6.3 or 8.0 is on the cleanest syntax.
  • An identity source that speaks SCIM 2.0. This guide uses FortiAuthenticator 6.6 or later as the reference client because it is the documented Fortinet-to-Fortinet path. Entra ID and Okta enterprise applications work with the same FortiGate-side configuration.
  • A server certificate on the FortiGate whose subject or SAN matches the name the SCIM client will connect to. Self-signed works in a lab. In production, use a certificate the client will actually trust.
  • Working NTP on both ends. SCIM itself is time-tolerant, but the SAML binding you build in Phase 5 is not.
  • Lab platform: anything that runs FortiGate-VM and FortiAuthenticator-VM. EVE-NG, Proxmox, VMware ESXi, or KVM are all fine. Two vCPU and 2 GB RAM per VM is enough for a functional test.

2.3 Component Table

Component Role Address / FQDN
FGT-EDGE-01 FortiGate. SCIM server, SAML service provider, policy enforcement point. port1 (WAN) 198.18.10.10/24
port2 (LAN) 10.0.10.1/24
loopback lo-scim 10.0.99.1/32
FAC-IDP-01 FortiAuthenticator. SCIM client (provisioning source) and SAML identity provider. 10.0.20.10/24
idp.infosecmonkey.lab
SCIM published endpoint Optional VIP used only when the SCIM client is a cloud IdP that must reach the FortiGate from the internet. 198.18.10.20 (VIP)
scim.infosecmonkey.lab
DC-01 Active Directory. Authoritative user store that feeds FortiAuthenticator. 10.0.30.10/24
NTP-01 Time source for all identity components. 10.0.30.5/24
Test client Workstation used to validate SAML login and policy matching. 10.0.50.0/24

2.4 Logical Flow

  PROVISIONING PLANE (push, out of band, continuous)
  ---------------------------------------------------
   AD / HR source          FortiAuthenticator            FortiGate
   10.0.30.10        --->  10.0.20.10 (SCIM client) ---> 10.0.99.1 (SCIM server)
                           POST   /scim/v2/Users
                           POST   /scim/v2/Groups
                           PATCH  /scim/v2/Groups/{id}
                           DELETE /scim/v2/Users/{id}

  AUTHENTICATION PLANE (pull, on demand, per user)
  ---------------------------------------------------
   Test client  --->  FortiGate SAML SP  --->  FAC SAML IdP  --->  assertion
   10.0.50.0/24       user saml "SCIM-SAML"                        back to SP
                        |
                        +-- set scim-client "SCIM-SRV-FAC"   <-- the join | v user group "grp-saml-it" --> firewall policy / SSL VPN portal

The two planes are independent. Provisioning keeps running whether or not anyone logs in, and authentication still works if provisioning stalls, it just falls back to whatever the assertion carries. The set scim-client line inside the SAML object is the single point where they meet.

3. Step-by-Step Implementation Workflow

Phase 1: Prepare the FortiGate

The Goal: Confirm you are on a build that has the feature, lock down time sync, and stage the certificates before anything else. Ninety percent of SCIM failures in the field are certificate or clock problems wearing a costume.

The Action: Verify firmware, verify the CLI tree exists in your VDOM, set NTP, and import the certificate material.

FORTIOS CLI
# Confirm the running build
get system status | grep -i version

# Confirm the SCIM table exists in this VDOM
config vdom
    edit <your_vdom>
        config user scim
            end
    next
end

# Lock time to a reliable source
config system ntp
    set ntpsync enable
    set type custom
    set syncinterval 60
    config ntpserver
        edit 1
            set server "10.0.30.5"
        next
    end
end

# Verify the clock actually moved
execute time
execute date
diagnose sys ntp status

Now stage the certificates. You need two distinct things, and people routinely conflate them:

What FortiOS store Why you need it
FortiGate server certificate certificate local Presented to the SCIM client during the TLS handshake. The CN or SAN must match the hostname in the base URL.
SCIM client certificate certificate remote Referenced by the SCIM client entry so the FortiGate can validate the identity of the thing provisioning into it.
Issuing CA chain certificate ca Required if either certificate above is issued by a private CA.

GUI Verification: Navigate to System > Certificates. Confirm your server certificate appears under Local Certificates with a valid date range, and that any private CA appears under Remote CA Certificates or External CA Certificates. If System > Certificates is not visible, enable it under System > Feature Visibility.

Phase 2: Enable the SCIM Service Listener

The Goal: Stand up the SCIM listener, pin it to a certificate, and expose it on exactly one interface, no more.

The Action: The listener has two halves. Global settings define the ports and the certificate. Interface administrative access defines where the daemon will actually accept a socket. Both are required. Setting only one produces a listener nobody can reach, or a reachable port with no service behind it.

FORTIOS CLI
# --- Global SCIM service settings ---
config system global
    set scim-https-port <scim_https_port>
    set scim-http-port  <scim_http_port>
    set scim-server-cert "<your_local_cert>"
end

# Example values used throughout this guide:
#   scim-https-port  8443
#   scim-http-port   8080   (do not expose this; see note below)
#   scim-server-cert "SCIM-Server-Cert"

Do not assume the default ports. They have shifted between maintenance releases and they collide with other FortiOS services depending on what else you have enabled. Set both values explicitly, write them into your build standard, and keep the HTTP port on a value you never permit through any interface. Bearer tokens and Basic credentials cross this channel. Plaintext SCIM is a credential disclosure waiting for a packet capture.

Next, expose the service. The cleanest pattern is a dedicated loopback so the listener is not bound to a physical interface whose addressing or role may change later.

FORTIOS CLI
# --- Dedicated loopback for the SCIM listener ---
config system interface
    edit "lo-scim"
        set vdom "<your_vdom>"
        set ip 10.0.99.1 255.255.255.255
        set allowaccess scim
        set type loopback
        set role lan
        set description "SCIM provisioning endpoint - do not repurpose"
    next
end

# --- Or, if you are binding to an existing data interface ---
# WARNING: allowaccess REPLACES the list. Re-state every service you still need.
config system interface
    edit "port2"
        set allowaccess ping https ssh fgfm scim
    next
end

Because the SCIM listener is local-in traffic, an allowaccess entry is a wide-open door on that interface. Constrain it by source with a local-in policy so only the provisioning host can knock.

FORTIOS CLI
config firewall address
    edit "ADDR-SCIM-CLIENT-FAC"
        set subnet 10.0.20.10 255.255.255.255
        set comment "FortiAuthenticator SCIM provisioning source"
    next
end

config firewall service custom
    edit "SVC-SCIM-HTTPS"
        set tcp-portrange <scim_https_port>
    next
end

config firewall local-in-policy
    edit 10
        set intf "lo-scim"
        set srcaddr "ADDR-SCIM-CLIENT-FAC"
        set dstaddr "all"
        set service "SVC-SCIM-HTTPS"
        set schedule "always"
        set action accept
        set comments "Permit SCIM provisioning from FAC only"
    next
    edit 11
        set intf "lo-scim"
        set srcaddr "all"
        set dstaddr "all"
        set service "ALL"
        set schedule "always"
        set action deny
        set comments "Deny all other SCIM endpoint access"
    next
end

GUI Verification: Two places. First, System > Settings, scroll to the SCIM Settings section and confirm the HTTP port, HTTPS port, and Server certificate reflect what you set, then click Apply. Second, Network > Interfaces, edit the interface, and confirm SCIM is ticked under Administrative Access. If the SCIM checkbox is missing entirely, you are on a build without the feature or in a VDOM where it is not applicable.

Phase 3: Create the SCIM Client Entry

The Goal: Define the one identity source permitted to provision into this VDOM, along with how it authenticates and whether its certificate identity is enforced.

The Action: Create the entry under config user scim. Note that the attribute names changed at 7.6.2, so pick the block that matches your firmware.

FortiOS 7.6.2 and later (including 7.6.3 and 8.0)

FORTIOS CLI
config user scim
    edit "SCIM-SRV-FAC"
        set status enable
        set base-url "https://<scim_fqdn>:<scim_https_port>/scim/v2"
        set auth-method base
        set secret "<shared_secret_or_password>"
        set certificate "<remote_cert_name>"
        set client-identity-check enable
    next
end

FortiOS 7.6.0 and 7.6.1 (legacy attribute names)

FORTIOS CLI
config user scim
    edit "SCIM-SRV-FAC"
        set status enable
        set base-url "https://<scim_fqdn>:<scim_https_port>/scim/v2"
        set client-authentication-method base
        set client-secret-token "<shared_secret_or_password>"
        set certificate "<remote_cert_name>"
        set client-identity-check enable
    next
end

Attribute reference

Attribute Values What it actually controls
status enable / disable Administrative on-off for this client relationship. Disabling stops new provisioning but does not automatically purge what was already provisioned.
base-url string The SCIM 2.0 base URL for this relationship. This is the exact value you paste into the identity provider as the Tenant URL or SCIM endpoint. Include the port if you moved off 443, and make sure the hostname matches the server certificate.
auth-method
(7.6.0/7.6.1: client-authentication-method)
token / base token expects an HTTP Authorization: Bearer header. This is what Entra ID and Okta use. base is HTTP Basic authentication and is the typical FortiAuthenticator pairing.
secret
(7.6.0/7.6.1: client-secret-token)
password string The bearer token or the Basic credential, depending on the method above. Masked in show output. Treat it as a privileged credential with a rotation schedule.
certificate remote cert name The client certificate the FortiGate expects this SCIM client to present. Pulled from the certificate remote store.
client-identity-check enable / disable Enforces validation of the client certificate identity on top of the bearer or Basic credential. Leave it enabled anywhere the provisioning path crosses untrusted ground. Disable it only while you are isolating a TLS problem, and turn it back on.
id integer Internal identifier surfaced by the diagnostic commands. Normally auto-assigned. You will see it in diagnose test scim list-clients output.

GUI Verification: Go to User & Authentication > SCIM Clients and click Create New. Set Status to Enabled, enter a Name, then fill in the base URL, authentication method, secret, and certificate options. The list view should show your entry with a green enabled indicator. If the SCIM Clients menu item is absent on 7.6.1 or later, check System > Feature Visibility.

Phase 4: Configure the Provisioning Source

The Goal: Point the identity provider at the FortiGate and trigger the first full synchronization.

Option A: FortiAuthenticator (the documented Fortinet-to-Fortinet path)

The Action: On FortiAuthenticator, log in with an administrative account and navigate to Authentication > SCIM > Service Provider. Click Create New and configure:

  • Name: a label that will show up in FortiAuthenticator logs. Use the FortiGate hostname, for example FGT-EDGE-01-SCIM.
  • SCIM base URL: exactly the string from set base-url in Phase 3. Character for character. Trailing slashes matter.
  • Authentication method: match what you set on the FortiGate. Basic pairs with auth-method base, bearer token pairs with auth-method token.
  • Credential: the same value you configured as secret.
  • Scope: select the groups you intend to provision. Do not select everything. Provisioning your entire directory into a firewall is an operational and privacy decision, not a convenience one.

Save the entry. Then double-click the newly created entry to open its settings pane and click Sync. This is the step people miss. Saving the service provider definition establishes the relationship; it does not push anything. The Sync action performs the initial bulk load of existing users and groups. From that point forward, FortiAuthenticator sends incremental changes as they happen.

Option B: Entra ID or Okta

The Action: The FortiGate-side configuration is identical. In the IdP, create an enterprise application, enable automatic provisioning, and supply:

IdP field FortiGate value
Tenant URL / SCIM connector base URL The base-url string
Secret token The secret value, with auth-method token on the FortiGate
Test Connection Must succeed before you assign users. This performs a live authenticated request against the endpoint.

Cloud IdP reachability. A SaaS identity provider cannot reach 10.0.99.1. You will need a VIP that publishes the SCIM port on a routable address (198.18.10.20 in the component table), a firewall policy permitting it, and either an allow-list of the IdP publishing IP ranges or an equivalent control. Publish the smallest possible surface. This endpoint accepts writes to your identity store.

Phase 5: Bind SCIM to the SAML Object

The Goal: Connect the provisioned directory to the authentication path so that a SAML login resolves against known users and known groups instead of raw assertion attributes.

The Action: This is a one-line change to an existing SAML user object, and it is the entire point of the exercise. Without it, you have a nicely populated directory that nothing consults.

FORTIOS CLI
config user saml
    edit "SCIM-SAML"
        set cert "<fgt_saml_signing_cert>"
        set entity-id "https://<fgt_fqdn>/saml/metadata"
        set single-sign-on-url "https://<fgt_fqdn>/saml/login"
        set single-logout-url "https://<fgt_fqdn>/saml/logout"
        set idp-entity-id "https://<idp_fqdn>/saml-idp/<portal>/metadata/"
        set idp-single-sign-on-url "https://<idp_fqdn>/saml-idp/<portal>/login/"
        set idp-single-logout-url "https://<idp_fqdn>/saml-idp/<portal>/logout/"
        set idp-cert "<idp_signing_cert>"
        set user-name "username"
        set group-name "group"

        # --- The join. This is the whole guide in one line. ---
        set scim-client "SCIM-SRV-FAC"
    next
end

GUI Verification: Navigate to User & Authentication > Single Sign-On. Edit your existing SAML entry, or click Create New. Expand the Additional SAML Attributes section, toggle SCIM client on, and select your client from the dropdown. If the dropdown is empty, your SCIM client entry in Phase 3 is either disabled or in a different VDOM.

Phase 6: Consume Provisioned Groups in Policy

The Goal: Turn provisioned group membership into enforceable policy. You have two patterns, and the choice is a security decision.

Pattern 1: Permit everyone the IdP authenticates

Reference the SAML object directly as a group member. Every SCIM group the client provisioned is in scope and every authenticated user passes. Fast to build, blunt to operate, and rarely what an auditor wants to see.

FORTIOS CLI
config user group
    edit "grp-saml-all"
        set member "SCIM-SAML"
    next
end

Pattern 2: Restrict to specific provisioned groups (recommended)

Use a config match block to bind the group to a named remote group. This is where SCIM earns its keep: the group name below exists on the FortiGate because SCIM put it there, not because someone typed it and hoped.

FORTIOS CLI
config user group
    edit "grp-saml-it"
        set member "SCIM-SAML"
        config match
            edit 1
                set server-name "SCIM-SAML"
                set group-name "IT"
            next
        end
    next
end

config user group
    edit "grp-saml-contractors"
        set member "SCIM-SAML"
        config match
            edit 1
                set server-name "SCIM-SAML"
                set group-name "Contractors"
            next
        end
    next
end

Now reference those groups anywhere FortiOS accepts a user group: a firewall policy, an SSL VPN portal mapping, a proxy policy, or a ZTNA rule.

FORTIOS CLI
config firewall policy
    edit 0
        set name "IT-Admin-Access-to-DC"
        set srcintf "ssl.root"
        set dstintf "port2"
        set srcaddr "all"
        set dstaddr "ADDR-DATACENTER"
        set action accept
        set schedule "always"
        set service "ALL"
        set groups "grp-saml-it"
        set logtraffic all
        set nat disable
    next
end

GUI Verification: Go to User & Authentication > User Groups and click Create New. Leave Type as Firewall, name the group, and in the Remote Groups section click Add. Set Remote Server to your SAML object (SCIM-SAML), set Groups to Specify, and pick the provisioned group from the list. If that list is populated, SCIM is working. If it is empty, stop and go to Section 4 before configuring anything else.

4. Verification & Validation

FortiOS ships three purpose-built diagnostics for this feature. Run them in order. Each one answers a different question, and a failure at one level makes everything below it meaningless.

4.1 Is the client relationship registered?

FORTIOS CLI
FGT-EDGE-01 # diagnose test scim list-clients

There are 1 clients in vdom.
id:1 name:SCIM-SRV-FAC

Success looks like: a non-zero client count and your entry name. Note the phrase in vdom. This command is VDOM-scoped. If you get zero clients on a multi-VDOM box, you are almost certainly in the wrong VDOM, not missing a configuration.

4.2 Did groups arrive?

FORTIOS CLI
FGT-EDGE-01 # diagnose test scim list-groups

SCIM-SRV-FAC
IT
Contractors
total:2

Success looks like: the client name followed by every group in scope and a total. Copy these strings exactly. Whatever appears here is what set group-name must contain in Phase 6. Not the AD display name, not the distinguished name, this string.

4.3 Did users arrive?

FORTIOS CLI
FGT-EDGE-01 # diagnose test scim list-users

SCIM-SRV-FAC
jdoe
asmith
mrivera
contractor01

Success looks like: the usernames you scoped in Phase 4. Now go disable one of those accounts in the identity source, wait for the sync interval, and run the command again. If the user disappears, your de-provisioning path is proven. That single test is worth more to an auditor than the entire rest of this build.

4.4 Transport and end-to-end validation

FORTIOS CLI
# Are the provisioning packets even arriving? Run this, then hit Sync on the IdP.
diagnose sniffer packet any "host 10.0.20.10 and tcp port <scim_https_port>" 4 0 l

# Is the local-in path permitting them?
diagnose debug flow filter addr 10.0.20.10
diagnose debug flow filter port <scim_https_port>
diagnose debug flow trace start 20
diagnose debug enable
# ... reproduce, then always:
diagnose debug disable
diagnose debug reset

# Which debug applications exist on your build? Names vary by release.
diagnose debug application ?

# After a test login, confirm the user landed in the right group
diagnose firewall auth list
execute log filter category 1
execute log filter field subtype "user"
execute log display

GUI Verification: After a successful SAML login, open Dashboard > Assets & Identities > Firewall Users. The authenticated user should appear with the correct group name in the Group column, and the method should show as the SAML server. Cross-check Log & Report > Events > User Events for the authentication and group-assignment entries.

5. Troubleshooting & “Gotchas”

Gotcha 1: The 7.6.2 attribute rename silently breaks your automation

Symptom: A FortiManager script, Ansible playbook, or Terraform plan that provisioned SCIM clients perfectly on 7.6.1 starts throwing Unknown action 0 or command parse error after an upgrade. Or worse, the entry gets created with a blank credential and fails authentication with no obvious cause.

Cause: Between 7.6.0/7.6.1 and 7.6.2, client-authentication-method became auth-method and client-secret-token became secret. The values and semantics did not change. Only the keys did.

Resolution: Never guess at the schema. Ask the box.

FORTIOS CLI
config user scim
    edit "SCIM-SRV-FAC"
        get              # shows the live attribute names on THIS build
        set ?            # enumerates every valid key
    next
end

# Then confirm what actually persisted
show full-configuration user scim

Add a firmware-version conditional to your automation, or pin the SCIM client configuration to a single tested release train. Because secret is a masked field, a partially applied template will not visually differ from a correct one. Always follow an automated push with diagnose test scim list-clients and a live sync, not just a config diff.

Gotcha 2: Everything is configured, nothing is listening

Symptom: The IdP’s Test Connection times out or returns a connection-refused error. diagnose test scim list-clients shows your client, but list-groups and list-users come back empty forever.

Cause: Three independent failures produce identical symptoms, which is why this one eats afternoons:

  1. scim was never added to allowaccess on the interface that owns the destination address.
  2. It was added, but the operator wrote set allowaccess scim on a production interface and wiped out https and ssh in the process. That attribute replaces, it does not append. If you just locked yourself out of a remote FortiGate, this is why.
  3. The client is connecting to a port that does not match scim-https-port, usually because the port lives in config system global but the URL lives in config user scim and only one of them got updated.

Resolution: Prove each layer separately rather than staring at the config.

FORTIOS CLI
# 1. What ports and cert are actually in effect?
show system global | grep -i scim

# 2. Which interfaces admit SCIM right now?
show system interface | grep -B10 scim

# 3. Is anything bound to the port?
diagnose sys tcpsock | grep <scim_https_port>

# 4. Does the URL agree with global settings?
show full-configuration user scim | grep base-url

# 5. Are packets arriving at all?
diagnose sniffer packet any "tcp port <scim_https_port>" 4 0 l

Standing rule: before you ever touch allowaccess on a remote device, run show system interface <name>, copy the existing list, and re-state it in full with your addition appended. Better still, put SCIM on its own loopback and never edit a production interface for this at all.

Gotcha 3: TLS handshake fails when client-identity-check is enabled

Symptom: Packets arrive, you see the TCP handshake complete in the sniffer, and then the connection tears down immediately. The IdP reports a certificate or SSL error rather than an authentication error. Setting client-identity-check disable makes the problem vanish.

Cause: Almost always one of these four, in descending order of frequency:

  • The client certificate was imported into certificate ca instead of certificate remote, so set certificate is referencing the wrong object or nothing at all.
  • The issuing CA chain is incomplete. Intermediates are missing from certificate ca.
  • The hostname in base-url does not appear in the FortiGate server certificate’s CN or SAN, so the client rejects the server before authentication is ever attempted. Connecting by IP against a certificate issued for an FQDN is the classic version of this.
  • Clock skew. A certificate that is not yet valid or is thirty minutes expired fails validation with an error message that mentions neither time nor certificates.

Resolution:

FORTIOS CLI
# Confirm the remote store actually contains the client cert
show certificate remote | grep -i name

# Confirm the CA chain is present
show certificate ca | grep -i name

# Confirm clocks agree on BOTH ends before blaming certificates
execute date
execute time
diagnose sys ntp status

# From the client side (FAC shell or any Linux host), inspect what
# the FortiGate is actually presenting:
#   openssl s_client -connect <scim_fqdn>:<scim_https_port> -servername <scim_fqdn>

Disabling client-identity-check is a valid isolation step to prove the fault is certificate-related. It is not a fix. Once you have identified the real cause, re-enable it. You are protecting a write-capable endpoint into your identity store, and a bearer token alone is a single factor sitting in someone’s configuration backup.

Gotcha 4: Groups provision successfully but policy never matches

Symptom: diagnose test scim list-groups returns exactly what you expect. Users authenticate through SAML without error. But the firewall policy keyed to grp-saml-it never matches, and traffic falls through to the implicit deny.

Cause: The string in set group-name does not byte-for-byte equal what SCIM provisioned. Common variants: someone typed the AD sAMAccountName instead of the SCIM display name, the group has a space in it and got truncated, case differs, or the group was renamed on the IdP after the FortiGate policy was written. A rename on the IdP side does not update the string in your config match block. It orphans it, silently.

Resolution: Treat diagnose test scim list-groups as the authoritative source and copy from it directly.

FORTIOS CLI
# 1. Get the authoritative strings
diagnose test scim list-groups

# 2. Compare against what policy is looking for
show full-configuration user group | grep -A6 "config match"

# 3. Quote any group name containing spaces or punctuation
config user group
    edit "grp-saml-fieldops"
        config match
            edit 1
                set server-name "SCIM-SAML"
                set group-name "Field Operations"
            next
        end
    next
end

# 4. After a test login, confirm the resolved group on the session
diagnose firewall auth list

# 5. If a stale session is masking the fix, clear and retest
diagnose firewall auth clear

Build a change-control dependency for this. Group renames in the identity source are a FortiGate change, whether or not anyone on the identity team believes that. If you run more than a handful of these, script a weekly comparison of list-groups output against every group-name referenced in your configuration and alert on orphans.

Gotcha 5: De-provisioning does not evict live sessions

Symptom: A user is disabled in the identity source. diagnose test scim list-users confirms they are gone from the FortiGate. And they are still moving traffic through a policy that requires their group.

Cause: SCIM manages the directory. It does not manage the session table. An authenticated firewall user entry, an SSL VPN tunnel, and an established session all persist independently of the identity record that created them, until an idle timeout, a hard timeout, or an administrative action ends them. This is not a defect; it is a separation of concerns. But if your offboarding runbook stops at “disabled in the IdP,” you have a control gap with a measurable duration.

Resolution: Shorten the window with timeouts, and close it immediately with an eviction step.

FORTIOS CLI
# Shorten the exposure window
config system global
    set auth-session-limit block-new
end

config user setting
    set auth-timeout 30              # minutes of idle before re-auth
    set auth-timeout-type idle-timeout
end

# See who is currently authenticated
diagnose firewall auth list

# Immediate eviction, all authenticated users
diagnose firewall auth clear

# SSL VPN specific
execute vpn sslvpn list
execute vpn sslvpn del-tunnel <index>

# Verify the directory really did drop them
diagnose test scim list-users

Automate it. A FortiGate automation stitch triggered on the relevant user event, with an action that clears the authenticated session, converts a manual runbook step into an enforced control. Build it, then test it by actually disabling a real test account and timing how long the session survives. Document that number. It is the honest answer to “how fast can you revoke access,” and it is almost never what people assume.

6. Deployment Checklist

# Item Proof
1 Firmware is 7.6.1 or later and CLI attribute names confirmed on the box get system status, set ?
2 NTP synchronized on FortiGate and identity provider diagnose sys ntp status
3 Server cert CN or SAN matches the hostname in base-url openssl s_client from the client side
4 SCIM ports set explicitly, HTTP port not exposed on any interface show system global | grep scim
5 Listener on a dedicated loopback, constrained by local-in policy show firewall local-in-policy
6 client-identity-check enabled in the final state show full-configuration user scim
7 Initial sync executed and users plus groups landed diagnose test scim list-users / list-groups
8 SAML object bound with set scim-client show user saml
9 Group names in config match copied verbatim from diagnostics Successful test login with correct group in diagnose firewall auth list
10 De-provisioning tested end to end, revocation time documented Disable a test account, time the session teardown

7. Closing Notes

SCIM on FortiOS is a small feature with an outsized effect on how identity-aware policy actually behaves in production. It removes the two worst properties of assertion-only SAML: you can no longer write a policy against a group that does not exist, and you no longer depend on someone remembering to tell the network team that a group got renamed.

Two things are worth internalizing before you roll this out at scale. First, the FortiGate is the SCIM server even though the configuration object is called a client, and every troubleshooting instinct you have will be backwards until that lands. Second, this endpoint accepts authenticated writes into the identity store that gates your firewall policy. Treat the credential, the certificate, and the exposed port with the same rigor you would apply to an administrative interface, because functionally that is what it is.

Verify the CLI attribute names against your specific build before you commit anything to a template. The schema moved once already between 7.6.1 and 7.6.2, and set ? costs you three seconds.


InfoSecMonkey — No fluff. Just the config that works.

Tested against FortiOS 7.6.x. All addresses use RFC 2544 documentation space (198.18.0.0/15) for public ranges and RFC 1918 space (10.0.0.0/16) for internal ranges. Replace every <placeholder> with values from your own environment.

Recent posts

  • If you've spent any time configuring user authentication on... Full Story

  • DNS is one of those technologies that quietly underpins... Full Story

  • BGP issues on FortiGate firewalls usually trace back to... Full Story

  • Every time your laptop talks to your router, a... Full Story

  • If you've spent any time configuring NAT on a... Full Story

  • If you have spent any time configuring firewall policies... Full Story

  • High availability on FortiGate is one of those features... Full Story

  • If you've configured SD-WAN on a FortiGate, you've almost... Full Story

  • FortiLink is the management protocol that turns a FortiSwitch... Full Story

  • FortiSwitches are pretty rock solid from Mean Time Between... Full Story

  • This is a quicky tip.  Have you ever gone... Full Story

  • DNS is one of those quiet pieces of internet... Full Story

  • This article is an updated version of the previous... Full Story

  • You will add ns2 as a secondary (slave) BIND9... Full Story

  • In the process of deploying my lab, I needed... Full Story

  • RFC 8805, used to be known as Self-Correcting IP... Full Story

  • Years back, I wrote an article about certificate pinning. ... Full Story

  • FortiGates have the ability to send alerts to Microsoft... Full Story

  • In this post, I am going to walk through... Full Story

  • Troubleshooting VoIP on a FortiGate can feel like trying... Full Story

  • Prior to FortiOS 7.0, there were three commands to... Full Story

  • In this post, I am going to go over... Full Story

  • What we are going to do:  We are going... Full Story

  • Choosing between FGCP (FortiGate Clustering Protocol) and FGSP (FortiGate... Full Story

  • Creating a VLAN on macOS (The "Pro" Move) A... Full Story

  • This blog post explores the logic behind how macOS... Full Story

  • Pretty Fly for a Wi-Fi Tell My Wi-Fi Love... Full Story

  • Part of my daily gig is creating BoMs (Bill-of-Materials)... Full Story

  • ICMP introduces several security risks, but careful filtering, rate... Full Story

  • The command diag debug application dhcps -1 enables full... Full Story

  • In the world of FortiOS, execute tac report is... Full Story

  • LLDP; What is it The Link Layer Discovery Protocol... Full Story

  • What it actually does When you run diagnose fdsm... Full Story

  • Monkey Bites are bite-sized, high-impact security insights designed for... Full Story

  • I have run macOS in macOS with Parallels but... Full Story

  • Don't be confused with my other FortiNAC posts where... Full Story

  • This is the third session in a multi-part article... Full Story

  • Today I was configuring key-based authentication on a FortiGate... Full Story

  • Netcat, often called the "Swiss Army knife" of networking,... Full Story

  • At its core, IEEE 802.1X is a network layer... Full Story

  • In case you did not see the previous FortiNAC... Full Story

  • This is our 5th session where we are going... Full Story

  • Now that we have Wireshark installed and somewhat configured,... Full Story

  • The Philosophy of Packet Analysis Troubleshooting isn't about looking... Full Story

  • 1. Title & Executive Summary Objective dhcping sends a... Full Story

  • Objective: This guide shows how to use Scapy to... Full Story

  • Executive Summary ipcalc looks like a single, predictable command,... Full Story