Skip to main content
mriha
Staff
Staff
May 28, 2026

Troubleshooting Tip: FortiOS v7.6.3: /logincheck no longer returns a session cookie

  • May 28, 2026
  • 0 replies
  • 89 views

Description


This article describes REST API changes for /logincheck user-based authentication for FortiOS v7.6.3+.

Scope


FortiOS v7.6.3.


Solution


FortiOS exposes a REST API that requires a session token for every authenticated request. Historically, the standard way to obtain that token was a form POST to /logincheck. Starting with FortiOS 7.6.3, that endpoint no longer returns a usable session cookie, silently breaking any automation that relied on it.

The /logincheck POST still returns HTTP 200/302 with no error, but no APSCOOKIE_* cookie is issued.


Authentication:

POST https://<fortigate>/logincheck
Content-Type: application/x-www-form-urlencoded
username=apiuser&secretkey=fortinet


On older FortiOS releases, this returns a Set-Cookie header with an APSCOOKIE_* session token:

HTTP/1.1 302 Found
Set-Cookie: APSCOOKIE_<hash>=<token>; Path=/; Secure; HttpOnly
That cookie was then passed in every subsequent API call:
GET https://<fortigate>/api/v2/monitor/system/status
Cookie: APSCOOKIE_<hash>=<token>


To resolve this:


Replace /logincheck with /api/v2/authentication. The session cookie is now session_key_443_<hash> instead of APSCOOKIE_*. For POST/PUT/DELETE requests, also send ccsrf_token_443_<hash> as the X-CSRFTOKEN header.


On FortiOS v7.6.3+, a POST to /logincheck still succeeds at the HTTP level - no exception is raised, no error body is returned. But the Set-Cookie response header no longer carries an APSCOOKIE_* value.


Any subsequent API call made with those cookies returns 401 Unauthorized. Because the login step itself appears to succeed, this failure is easy to miss and hard to trace without inspecting raw response headers.

 
The correct approach is to use /api/v2/authentication.

POST https://<fortigate>/api/v2/authentication
Content-Type: application/json
{
"username": "apiuser",
"password": "fortinet"
}


A successful response:


HTTP/1.1 200 OK
Content-Type: application/json
Set-Cookie: session_key_443_<hash>=<token>; path=/; HttpOnly; SameSite=Strict; secure
Set-Cookie: ccsrf_token_443_<hash>=<csrf_token>; path=/; SameSite=Strict; secure
Set-Cookie: cmgmt_override_443_<hash>=...; path=/; SameSite=Strict; secure
{
"status_message": "LOGIN_SUCCESS",
"error": 0
}


The session key is session_key_443_<hash> - pass it as a cookie on every subsequent request. The CSRF token (ccsrf_token_443_<hash>) must additionally be sent as the X-CSRFTOKEN request header on any state-changing call (POST, PUT, DELETE).


GET https://<fortigate>/api/v2/monitor/system/status
Cookie: session_key_443_<hash>=<token>
# For POST/PUT/DELETE also add:
X-CSRFTOKEN: <ccsrf_token value>


CURL examples:

Login:

curl -sk -c cookies.txt \
  -X POST https://<fortigate>/api/v2/authentication \
  -H "Content-Type: application/json" \
  -d '{"username": "apiuser", "password": "fortinet"}'


Use a cookie to get system status:

curl -sk -b cookies.txt \
  https://<fortigate>/api/v2/monitor/system/status


POST/PUT/DELETE:

CSRF=$(awk '/ccsrf_token/ {print $NF}' cookies.txt)

curl -sk -b cookies.txt \
  -X POST https://<fortigate>/api/v2/cmdb/firewall/policy \
  -H "Content-Type: application/json" \
  -H "X-CSRFTOKEN: $CSRF" \
  -d '{"name": "test-policy"}'