Authentication Error (UNAUTHORIZED) when enrolling Identity (QuickStart Docker Compose)

Hello,

First of all, thank you for such an amazing product. I'm currently setting up a test environment following the QuickStart guide to get familiar with OpenZiti.

Goal: I am using Docker Compose on a server with a public IP. My goal is to add my home PC as an identity and establish a connection using Ziti Desktop Edge.

Steps Taken:

  1. Prepared the .env and docker-compose.yml (see below) and ran docker compose up.

  2. Created a new identity named pc1 via the Ziti Admin Console (ZAC).

  3. Downloaded pc1.jwt and imported it into Ziti Desktop Edge on my local PC.

The Problem: The identity pc1 fails to come online. Looking at the logs, it seems to be an authentication failure.

Client Logs (Ziti Desktop Edge): (Note: Some values are masked for privacy)

[2025-12-29T13:08:44.980Z]   DEBUG ziti-sdk:ziti_ctrl.c:504 ctrl_body_cb() ctrl[https://172.137.xxx.xxx:8441] completed GET[/current-identity] in 0.081 s
[2025-12-29T13:08:44.980Z]   ERROR ziti-sdk:ziti_ctrl.c:526 ctrl_body_cb() ctrl[https://172.137.xxx.xxx:8441] API request[/current-identity] failed code[UNAUTHORIZED] message[The request could not be completed. The session is not authorized or the credentials are invalid]
[2025-12-29T13:08:44.980Z]   ERROR ziti-sdk:ziti.c:1568 update_identity_data() ztx[1] failed to get identity_data: The request could not be completed. The session is not authorized or the credentials are invalid[UNAUTHORIZED]
[2025-12-29T13:08:44.980Z]    WARN ziti-sdk:ziti.c:1570 update_identity_data() ztx[1] api session is no longer valid. Trying to re-auth
[2025-12-29T13:08:44.980Z]    WARN ziti-sdk:ziti.c:224 ziti_set_unauthenticated() ztx[1] auth error: The request could not be completed. The session is not authorized or the credentials are invalid
[2025-12-29T13:08:44.980Z]   DEBUG ziti-sdk:ziti.c:227 ziti_set_unauthenticated() ztx[1] setting auth_state[0] to 0
[2025-12-29T13:08:44.980Z]   DEBUG ziti-sdk:ziti_ctrl.c:380 ziti_ctrl_clear_auth() ctrl[https://172.137.xxx.xxx:8441] clearing api session token for ziti_controller
[2025-12-29T13:08:44.980Z]    WARN tunnel-cbs:ziti_tunnel_ctrl.c:1018 on_ziti_event() ziti_ctx controller connections failed: failed to authenticate
[2025-12-29T13:08:44.980Z]    INFO ziti-edge-tunnel:ziti-edge-tunnel.c:460 on_event() ztx[.../netfoundry/pc1.json] context event : status is failed to authenticate
[2025-12-29T13:08:44.980Z]   ERROR ziti-edge-tunnel:ziti-edge-tunnel.c:514 on_event() ztx[.../netfoundry/pc1.json] failed to connect to controller due to failed to authenticate
[2025-12-29T13:08:44.980Z]   DEBUG ziti-edge-tunnel:ipc_event.c:119 send_events_message() Events Message => {"Op":"identity","Action":"added","Fingerprint":"[MASKED_FINGERPRINT]","Id":{"Name":"pc1","Identifier":".../netfoundry/pc1.json","FingerPrint":"[MASKED_FINGERPRINT]","Active":true,"Loaded":true,"IdFileStatus":false,"NeedsExtAuth":false,"MfaEnabled":false,"MfaNeeded":false,"Metrics":{"Up":0,"Down":0},"MfaMinTimeout":0,"MfaMaxTimeout":0,"MfaMinTimeoutRem":0,"MfaMaxTimeoutRem":0,"MinTimeoutRemInSvcEvent":0,"MaxTimeoutRemInSvcEvent":0,"Deleted":false,"Notified":false}}
[2025-12-29T13:08:44.980Z]   DEBUG ziti-edge-tunnel:ipc_event.c:119 send_events_message() Events Message => {"Op":"controller","Action":"disconnected","Identifier":".../netfoundry/pc1.json","Fingerprint":"[MASKED_FINGERPRINT]"}
[2025-12-29T13:08:44.980Z]   DEBUG ziti-sdk:ziti.c:452 ziti_force_api_session_refresh() ztx[1] forcing session refresh
[2025-12-29T13:08:44.980Z]   DEBUG ziti-sdk:oidc.c:644 refresh_time_cb() oidc[internal] refreshing OIDC token
[2025-12-29T13:08:44.980Z]   TRACE ziti-sdk:ziti.c:1778 ztx_prep_deadlines() ztx[1] processing deadlines in 19910
[2025-12-29T13:08:44.980Z]   TRACE ziti-edge-tunnel:ipc_event.c:103 on_write_event() Events message is sent.
[2025-12-29T13:08:44.980Z]   TRACE ziti-edge-tunnel:ipc_event.c:103 on_write_event() Events message is sent.
[2025-12-29T13:08:44.980Z]   TRACE ziti-edge-tunnel:ipc_event.c:103 on_write_event() Events message is sent.
[2025-12-29T13:08:44.980Z]   TRACE ziti-edge-tunnel:ipc_event.c:103 on_write_event() Events message is sent.
[2025-12-29T13:08:44.980Z]   TRACE ziti-sdk:ziti.c:1778 ztx_prep_deadlines() ztx[1] processing deadlines in 19909
[2025-12-29T13:08:44.994Z] VERBOSE ziti-sdk:ziti_ctrl.c:200 ctrl_resp_cb() ctrl[https://172.137.xxx.xxx:8441] received headers GET[/current-identity/edge-routers?limit=25&offset=0]
[2025-12-29T13:08:44.994Z] VERBOSE ziti-sdk:ziti_ctrl.c:431 ctrl_body_cb() ctrl[https://172.137.xxx.xxx:8441] HTTP RESPONSE: {"error":{"cause":{"code":"UNHANDLED","message":"UNAUTHORIZED: ..."},"code":"UNAUTHORIZED","message":"...","requestId":"[MASKED_ID]"},"meta":{"apiEnrollmentVersion":"0.0.1","apiVersion":"0.0.1"}}

Server Logs (ziti-controller):

ziti-controller-1  | [ 622.512]  ERROR ziti/controller/model.(*AuthModuleCert).Process: {authMethod=[cert] fingerprint=[7de14ef93d94...]} failed to find authenticator by fingerprint
ziti-controller-1  | [ 632.523]  ERROR ziti/controller/model.(*AuthModuleCert).Process: {authMethod=[cert] fingerprint=[7de14ef93d94...]} failed to find authenticator by fingerprint

Environment:

  • OS: Ubuntu 25.10 (questing)

  • Docker: v29.1.3

  • OpenZiti: Controller v1.5.9 / ZAC v3.12.9

root@localhost:~# docker --version
Docker version 29.1.3, build f52814d

root@localhost:/work# lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description:    Ubuntu 25.10
Release:        25.10
Codename:       questing

Controller: v1.5.9 ZAC: 3.12.9

.env (172.137.xxx.xxx is the public IP of my server)

# OpenZiti Variables
ZITI_IMAGE=openziti/quickstart
ZITI_VERSION=latest

# the user and password to use
# Leave password blank to have a unique value generated or set the password explicitly
ZITI_USER=admin
ZITI_PWD=pwd1234

ZITI_INTERFACE=0.0.0.0

# controller name, address/port information
ZITI_CTRL_NAME=ziti-controller
ZITI_CTRL_EDGE_ADVERTISED_ADDRESS=172.237.xxx.xxx
ZITI_CTRL_ADVERTISED_ADDRESS=172.237.xxx.xxx
ZITI_CTRL_EDGE_IP_OVERRIDE=172.237.xxx.xxx
ZITI_CTRL_EDGE_ADVERTISED_PORT=8441
ZITI_CTRL_ADVERTISED_PORT=8440

# The duration of the enrollment period (in minutes), default if not set. shown - 7days
ZITI_EDGE_IDENTITY_ENROLLMENT_DURATION=10080
ZITI_ROUTER_ENROLLMENT_DURATION=10080

# router address/port information
ZITI_ROUTER_NAME=ziti-edge-router
ZITI_ROUTER_ADVERTISED_ADDRESS=172.237.xxx.xxx
ZITI_ROUTER_PORT=8442
ZITI_ROUTER_IP_OVERRIDE=172.237.xxx.xxx
#ZITI_ROUTER_LISTENER_BIND_PORT=8444
ZITI_ROUTER_ROLES=public

ZAC_CONTROLLER_URLS=https://172.237.xxx.xxx:8441

docker-compose.yml

Based on the simplified-docker-compose.yml from the official repo, with the following added to ziti-console: - ZAC_CONTROLLER_URLS=https://${ZITI_CTRL_EDGE_ADVERTISED_ADDRESS}:8441

(Rest of the file follows the standard QuickStart template)

services:
  ziti-controller:
    image: "${ZITI_IMAGE}:${ZITI_VERSION}"
    healthcheck:
      test: curl -m 1 -s -k -f https://${ZITI_CTRL_EDGE_ADVERTISED_ADDRESS:-ziti-edge-controller}:${ZITI_CTRL_EDGE_ADVERTISED_PORT:-1280}/edge/client/v1/version
      interval: 1s
      timeout: 3s
      retries: 30
    env_file:
      - ./.env
    ports:
      - ${ZITI_INTERFACE:-0.0.0.0}:${ZITI_CTRL_EDGE_ADVERTISED_PORT:-1280}:${ZITI_CTRL_EDGE_ADVERTISED_PORT:-1280}
      - ${ZITI_INTERFACE:-0.0.0.0}:${ZITI_CTRL_ADVERTISED_PORT:-6262}:${ZITI_CTRL_ADVERTISED_PORT:-6262}
    environment:
      - ZITI_CTRL_NAME=${ZITI_CTRL_NAME:-ziti-edge-controller}
      - ZITI_CTRL_EDGE_ADVERTISED_ADDRESS=${ZITI_CTRL_EDGE_ADVERTISED_ADDRESS:-ziti-edge-controller}
      - ZITI_CTRL_EDGE_ADVERTISED_PORT=${ZITI_CTRL_EDGE_ADVERTISED_PORT:-1280}
      - ZITI_CTRL_EDGE_IP_OVERRIDE=${ZITI_CTRL_EDGE_IP_OVERRIDE:-127.0.0.1}
      - ZITI_CTRL_ADVERTISED_PORT=${ZITI_CTRL_ADVERTISED_PORT:-6262}
      - ZITI_EDGE_IDENTITY_ENROLLMENT_DURATION=${ZITI_EDGE_IDENTITY_ENROLLMENT_DURATION}
      - ZITI_ROUTER_ENROLLMENT_DURATION=${ZITI_ROUTER_ENROLLMENT_DURATION}
      - ZITI_USER=${ZITI_USER:-admin}
      - ZITI_PWD=${ZITI_PWD}
    networks:
      ziti:
        aliases:
          - ziti-edge-controller
    volumes:
      - ziti-fs:/persistent
    entrypoint:
      - "/var/openziti/scripts/run-controller.sh"

  ziti-controller-init-container:
    image: "${ZITI_IMAGE}:${ZITI_VERSION}"
    depends_on:
      ziti-controller:
        condition: service_healthy
    environment:
      - ZITI_CTRL_EDGE_ADVERTISED_ADDRESS=${ZITI_CTRL_EDGE_ADVERTISED_ADDRESS:-ziti-edge-controller}
      - ZITI_CTRL_EDGE_ADVERTISED_PORT=${ZITI_CTRL_EDGE_ADVERTISED_PORT:-1280}
    env_file:
      - ./.env
    networks:
      ziti:
    volumes:
      - ziti-fs:/persistent
    entrypoint:
      - "/var/openziti/scripts/run-with-ziti-cli.sh"
    command:
      - "/var/openziti/scripts/access-control.sh"

  ziti-edge-router:
    image: "${ZITI_IMAGE}:${ZITI_VERSION}"
    env_file:
      - ./.env
    depends_on:
      ziti-controller:
        condition: service_healthy
    ports:
      - ${ZITI_INTERFACE:-0.0.0.0}:${ZITI_ROUTER_PORT:-3022}:${ZITI_ROUTER_PORT:-3022}
      - ${ZITI_INTERFACE:-0.0.0.0}:${ZITI_ROUTER_LISTENER_BIND_PORT:-10080}:${ZITI_ROUTER_LISTENER_BIND_PORT:-10080}
    environment:
      - ZITI_CTRL_ADVERTISED_ADDRESS=${ZITI_CTRL_ADVERTISED_ADDRESS:-ziti-controller}
      - ZITI_CTRL_ADVERTISED_PORT=${ZITI_CTRL_ADVERTISED_PORT:-6262}
      - ZITI_CTRL_EDGE_ADVERTISED_ADDRESS=${ZITI_CTRL_EDGE_ADVERTISED_ADDRESS:-ziti-edge-controller}
      - ZITI_CTRL_EDGE_ADVERTISED_PORT=${ZITI_CTRL_EDGE_ADVERTISED_PORT:-1280}
      - ZITI_ROUTER_NAME=${ZITI_ROUTER_NAME:-ziti-edge-router}
      - ZITI_ROUTER_ADVERTISED_ADDRESS=${ZITI_ROUTER_ADVERTISED_ADDRESS:-ziti-edge-router}
      - ZITI_ROUTER_PORT=${ZITI_ROUTER_PORT:-3022}
      - ZITI_ROUTER_LISTENER_BIND_PORT=${ZITI_ROUTER_LISTENER_BIND_PORT:-10080}
      - ZITI_ROUTER_ROLES=public
    networks:
      - ziti
    volumes:
      - ziti-fs:/persistent
    entrypoint: /bin/bash
    command: "/var/openziti/scripts/run-router.sh edge"

  ziti-console:
    image: openziti/zac
    working_dir: /usr/src/app
    environment:
      - ZAC_CONTROLLER_URLS=https://${ZITI_CTRL_EDGE_ADVERTISED_ADDRESS}:8441
      - ZAC_SERVER_CERT_CHAIN=/persistent/pki/${ZITI_CTRL_EDGE_ADVERTISED_ADDRESS:-ziti-edge-controller}-intermediate/certs/${ZITI_CTRL_EDGE_ADVERTISED_ADDRESS:-ziti-edge-controller}-server.cert
      - ZAC_SERVER_KEY=/persistent/pki/${ZITI_CTRL_EDGE_ADVERTISED_ADDRESS:-ziti-edge-controller}-intermediate/keys/${ZITI_CTRL_EDGE_ADVERTISED_ADDRESS:-ziti-edge-controller}-server.key
      - ZITI_CTRL_EDGE_ADVERTISED_ADDRESS=${ZITI_CTRL_EDGE_ADVERTISED_ADDRESS:-ziti-edge-controller}
      - ZITI_CTRL_EDGE_ADVERTISED_PORT=${ZITI_CTRL_EDGE_ADVERTISED_PORT:-1280}
      - ZITI_CTRL_NAME=${ZITI_CTRL_NAME:-ziti-edge-controller}
      - PORTTLS=8443
    depends_on:
      ziti-controller:
        condition: service_healthy
    ports:
      - ${ZITI_INTERFACE:-0.0.0.0}:8443:8443
    volumes:
      - ziti-fs:/persistent
    networks:
      - ziti

networks:
  ziti:

volumes:
  ziti-fs:

Hi @TanakaShunya, welcome to the community and to OpenZiti!

Thanks for providing the .env file... Looking at it, my inital reaction is that the docker example won't support the advertised address and ip overrides being the same thing. So I ended up testing it... It worked fine. (I honestly expected it to fail because the SANS will have both DNS and IP with the IP, which I expected to be a problem)... I was pleasantly surprised to find that not to be a problem:

My guess is that maybe you recreated the identity during testing? The ziti cli has a handy function that I also ran before trying a tunneler that can also help you test to make sure your overlay is setup properly: ziti ops verify traffic --mode both. Please run that and you'll feel better that you're setup is correct and somewhere along the way some sort of unexpected error happened.

Run that command and you'll see something that looks like this:

Here's my full .env file as well if you want to compare what I've done vs yours... It should be pretty much the same:

cat .env
# OpenZiti Variables
ZITI_IMAGE=openziti/quickstart
ZITI_VERSION=latest

# the user and password to use
# Leave password blank to have a unique value generated or set the password explicitly
ZITI_USER=admin
ZITI_PWD=password

ZITI_INTERFACE=0.0.0.0

# controller name, address/port information
ZITI_CTRL_NAME=ziti-controller
ZITI_CTRL_EDGE_ADVERTISED_ADDRESS=3.18.113.172
ZITI_CTRL_ADVERTISED_ADDRESS=3.18.113.172
ZITI_CTRL_EDGE_IP_OVERRIDE=3.18.113.172
ZITI_CTRL_EDGE_ADVERTISED_PORT=8741
ZITI_CTRL_ADVERTISED_PORT=8740

# router address/port information
ZITI_ROUTER_NAME=ziti-edge-router
ZITI_ROUTER_ADVERTISED_ADDRESS=3.18.113.172
ZITI_ROUTER_PORT=8742
ZITI_ROUTER_IP_OVERRIDE=3.18.113.172
ZITI_ROUTER_LISTENER_BIND_PORT=8744
ZITI_ROUTER_ROLES=public

ZAC_CONTROLLER_URLS=https://3.18.113.172:8741