← All Articles

SSO and Kerberos Setup Guide

Authentication Options Overview

IMTerm supports six authentication methods. Choose one (or combine them) based on your infrastructure:

Method When to use
Local accounts Small deployments, no AD, evaluation
LDAP / Active Directory Any organization with a Windows domain
OIDC Okta, Azure AD (Entra ID), Google Workspace, Keycloak
SAML ADFS, PingFederate, older enterprise IdPs
Kerberos SPNEGO Windows domain with zero-login browser SSO
mTLS client certificates High-security, air-gapped, smart-card environments

Multiple methods can run simultaneously. For example: LDAP for authentication + Kerberos for SSO means users authenticate with AD credentials AND get automatically signed in from domain-joined machines.


Local Accounts

Default method, no external dependencies.

auth:
  provider: local

Manage users with:

imterm user add --username admin --role admin
imterm user add --username jsmith --role user
imterm user list
imterm user disable --username jsmith

Passwords are stored as bcrypt hashes. Local accounts are always available as a fallback even when SSO is configured.


LDAP and Active Directory

Active Directory is an LDAP server. IMTerm binds to it using a service account and verifies user passwords via LDAP bind.

config.yaml:

auth:
  provider: ldap
  ldap:
    url: ldap://dc01.corp.com:389
    bind_dn: "CN=imterm-svc,OU=Service Accounts,DC=corp,DC=com"
    bind_password: "${LDAP_PASSWORD}"    # from environment variable
    base_dn: "OU=Users,DC=corp,DC=com"
    user_filter: "(sAMAccountName=%s)"
    group_base_dn: "OU=Groups,DC=corp,DC=com"
    group_filter: "(&(objectClass=group)(member=%s))"
    tls: false          # true for LDAPS (port 636)
    start_tls: false    # true for STARTTLS on port 389

  # Map AD groups to IMTerm roles
  role_mapping:
    admin: ["CN=IMTerm-Admins,OU=Groups,DC=corp,DC=com"]
    user:  ["CN=IMTerm-Users,OU=Groups,DC=corp,DC=com", "CN=Domain Users,DC=corp,DC=com"]

Test the connection before restarting IMTerm:

ldapsearch -H ldap://dc01.corp.com -D "CN=imterm-svc,OU=Service Accounts,DC=corp,DC=com" \
  -w "$(cat /etc/imterm/ldap-password)" \
  -b "OU=Users,DC=corp,DC=com" "(sAMAccountName=jsmith)"

A successful ldapsearch response confirms IMTerm can reach the DC and the bind account works.

For LDAPS (port 636):

ldap:
  url: ldaps://dc01.corp.com:636
  tls: true
  tls_skip_verify: false    # never true in production
  tls_ca_cert: /etc/imterm/certs/corp-root-ca.pem

Sync groups on login: When a user logs in, IMTerm queries their group membership and updates their role. No scheduled sync needed.


OIDC (Okta, Azure AD, Google Workspace)

Azure AD (Entra ID)

  1. In the Azure portal, navigate to App registrations > New registration
  2. Name: IMTerm, redirect URI: https://imterm.corp.com/auth/callback
  3. Under Certificates & secrets, create a new client secret
  4. Under API permissions, add openid, profile, email, User.Read
  5. Copy: Application (client) ID and Directory (tenant) ID

config.yaml:

auth:
  provider: oidc
  oidc:
    issuer_url: "https://login.microsoftonline.com/{tenant-id}/v2.0"
    client_id: "{application-client-id}"
    client_secret: "${OIDC_CLIENT_SECRET}"
    redirect_url: "https://imterm.corp.com/auth/callback"
    scopes: ["openid", "profile", "email", "offline_access"]
    username_claim: "preferred_username"    # or "email"

  # Map Azure AD groups to IMTerm roles (requires group_id, not name)
  role_mapping:
    admin: ["{azure-group-object-id-for-admins}"]
    user:  ["{azure-group-object-id-for-users}"]

Okta

  1. In Okta admin, create a new Web Application under Applications
  2. Grant type: Authorization Code
  3. Sign-in redirect URI: https://imterm.corp.com/auth/callback
  4. Copy Client ID and Client secret
auth:
  provider: oidc
  oidc:
    issuer_url: "https://your-org.okta.com"
    client_id: "{okta-client-id}"
    client_secret: "${OIDC_CLIENT_SECRET}"
    redirect_url: "https://imterm.corp.com/auth/callback"
    scopes: ["openid", "profile", "email", "groups"]
    groups_claim: "groups"    # Okta includes groups in the token

  role_mapping:
    admin: ["imterm-admins"]
    user:  ["imterm-users", "employees"]

Google Workspace

  1. In Google Cloud Console, create an OAuth 2.0 Client ID under APIs & Services > Credentials
  2. Application type: Web application
  3. Authorized redirect URI: https://imterm.corp.com/auth/callback
auth:
  provider: oidc
  oidc:
    issuer_url: "https://accounts.google.com"
    client_id: "{google-client-id}.apps.googleusercontent.com"
    client_secret: "${OIDC_CLIENT_SECRET}"
    redirect_url: "https://imterm.corp.com/auth/callback"
    scopes: ["openid", "profile", "email"]
    username_claim: "email"
    # Google does not include groups in OIDC tokens; use hd (hosted domain) claim
    hd_restriction: "corp.com"    # only allow users from this Google Workspace domain

SAML (ADFS, PingFederate)

ADFS Setup

  1. In ADFS Management, create a Relying Party Trust
  2. Import metadata from: https://imterm.corp.com/auth/saml/metadata
  3. Add claim rules to pass email and group membership
  4. Note the ADFS federation service name (e.g., adfs.corp.com)

config.yaml:

auth:
  provider: saml
  saml:
    entity_id: "https://imterm.corp.com"
    metadata_url: "https://adfs.corp.com/FederationMetadata/2007-06/FederationMetadata.xml"
    acs_url: "https://imterm.corp.com/auth/saml/callback"
    certificate: /etc/imterm/certs/imterm-saml.crt
    private_key: /etc/imterm/certs/imterm-saml.key
    name_id_format: "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress"
    # Attribute name for group membership in SAML assertion
    groups_attribute: "http://schemas.microsoft.com/ws/2008/06/identity/claims/groups"

  role_mapping:
    admin: ["IMTerm-Admins"]
    user:  ["IMTerm-Users"]

Generate a SAML signing certificate/key pair:

openssl req -x509 -newkey rsa:2048 -keyout imterm-saml.key -out imterm-saml.crt \
  -days 3650 -nodes -subj "/CN=imterm.corp.com"

Kerberos SPNEGO (Zero-Login Browser SSO)

Kerberos SPNEGO allows users on domain-joined machines to open IMTerm in their browser without entering a username or password. The browser presents the user's Kerberos ticket automatically.

Prerequisites

  • Active Directory domain
  • IMTerm server is Linux (domain membership not required)
  • Users are on Windows machines joined to the same AD domain

Step 1: Create a Service Account

In Active Directory Users and Computers, create a user account: - Username: imterm-svc - Password: set a strong password, mark "Password never expires" - Uncheck "User must change password at next login"

Step 2: Set the Service Principal Name (SPN)

Run from a Windows machine with AD admin rights:

setspn -S HTTP/imterm.corp.com corp\imterm-svc
setspn -S HTTP/imterm corp\imterm-svc

Verify:

setspn -L corp\imterm-svc

Step 3: Generate the Keytab

ktpass /out imterm.keytab /mapuser corp\imterm-svc@CORP.COM /princ HTTP/imterm.corp.com@CORP.COM /pass "ServiceAccountPassword" /ptype KRB5_NT_PRINCIPAL /crypto AES256-SHA1

Copy imterm.keytab to /etc/imterm/imterm.keytab on the IMTerm server.

Step 4: Configure krb5.conf on Linux

/etc/krb5.conf:

[libdefaults]
    default_realm = CORP.COM
    dns_lookup_realm = false
    dns_lookup_kdc = true
    forwardable = true

[realms]
    CORP.COM = {
        kdc = dc01.corp.com
        admin_server = dc01.corp.com
    }

[domain_realm]
    .corp.com = CORP.COM
    corp.com = CORP.COM

Test Kerberos connectivity from the IMTerm server:

kinit -kt /etc/imterm/imterm.keytab HTTP/imterm.corp.com@CORP.COM
klist    # should show the TGT

Step 5: Configure IMTerm

auth:
  provider: ldap    # still use LDAP for authorization/groups
  ldap:
    url: ldap://dc01.corp.com:389
    # ... (as above)

  # Kerberos adds SSO on top of LDAP auth
  kerberos:
    enabled: true
    keytab: /etc/imterm/imterm.keytab
    principal: "HTTP/imterm.corp.com@CORP.COM"
    realm: "CORP.COM"

Step 6: Configure Browsers for SPNEGO

Chrome and Edge: No configuration needed if the IMTerm URL is in the local intranet zone. To explicitly enable:

--auth-server-whitelist="imterm.corp.com"
--auth-negotiate-delegate-whitelist="imterm.corp.com"

Deploy via Group Policy: Computer Configuration > Administrative Templates > Google Chrome > HTTP Authentication > Authentication Server Whitelist

Firefox: Navigate to about:config and set: - network.negotiate-auth.trusted-uris = https://imterm.corp.com - network.negotiate-auth.delegation-uris = https://imterm.corp.com

Internet Explorer / Edge (legacy): Add imterm.corp.com to Trusted Sites in Internet Options.

Testing SPNEGO

From a domain-joined Windows machine: 1. Open a command prompt: klist should show cached Kerberos tickets 2. Open Chrome and navigate to https://imterm.corp.com 3. You should be logged in automatically - no login page appears 4. IMTerm logs IMTE1035I: Kerberos authentication success for user@CORP.COM

If you still see the login page, check: - The SPN is registered correctly (step 2) - The browser is configured for SPNEGO (step 6) - IMTerm's hostname matches the SPN exactly


mTLS Client Certificates

Mutual TLS (mTLS) requires users to present a client certificate in their browser or system certificate store. No username/password dialog.

Generate CA and Client Certificates

# Create CA
openssl genrsa -out ca.key 4096
openssl req -new -x509 -days 3650 -key ca.key -out ca.crt -subj "/CN=IMTerm CA"

# Create client certificate for user jsmith
openssl genrsa -out jsmith.key 2048
openssl req -new -key jsmith.key -out jsmith.csr -subj "/CN=jsmith/O=corp"
openssl x509 -req -days 730 -in jsmith.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out jsmith.crt

# Package as PKCS#12 for browser import
openssl pkcs12 -export -in jsmith.crt -inkey jsmith.key -out jsmith.p12 -passout pass:changeme

Configure IMTerm

tls:
  cert: /etc/imterm/certs/imterm.crt
  key: /etc/imterm/certs/imterm.key
  client_ca: /etc/imterm/certs/ca.crt    # require client certs

auth:
  provider: mtls
  mtls:
    # Map CN from certificate to IMTerm username
    username_field: cn      # or email (from SAN)
    # Map O from certificate to role
    role_mapping:
      admin: { organization: "imterm-admins" }
      user:  { organization: "corp" }

Install Client Certificate in Browser

Chrome/Edge: Import jsmith.p12 in Settings > Privacy & Security > Manage certificates > Import.

Firefox: Settings > Privacy & Security > Certificates > View Certificates > Your Certificates > Import.

When the user navigates to IMTerm, the browser presents the certificate and the user is authenticated automatically.


FIPS 140-2

For government and regulated environments requiring FIPS-compliant cryptography:

# Build with BoringCrypto (FIPS 140-2 validated)
make build-fips
# Produces: bin/imterm-fips

The FIPS binary uses BoringCrypto for all TLS operations. Verify:

bin/imterm-fips --version
# IMTerm v2.0.1 (abc1234) built 2026-06-27 with go1.22.4-fips

FIPS mode enforces: - TLS 1.2+ only (no TLS 1.0 or 1.1) - Approved cipher suites only (AES-GCM, ECDHE) - RSA keys 2048+ bits minimum - SHA-256+ for all certificate hashing


RBAC (Role-Based Access Control)

IMTerm has three roles:

Role Permissions
admin All settings, user management, view all sessions, terminate sessions, audit log
user Connect sessions, manage own connection profiles, view own print jobs
view-only Read-only access: view active sessions, cannot connect or change settings

Assign roles in local accounts or via group mapping in LDAP/OIDC/SAML.


Audit Log Events

Authentication events logged to the audit log (default: /var/log/imterm/audit.jsonl):

Event ID Description
IMTE1030I Local auth success
IMTE1031W Local auth failure
IMTE1032I LDAP auth success
IMTE1033W LDAP auth failure
IMTE1034I OIDC auth success
IMTE1035I Kerberos auth success
IMTE1036I SAML auth success
IMTE1037I mTLS auth success
IMTE1040W Authorization failure (wrong role)
IMTE1041I User logout
IMTE1050W Auth provider unreachable

All events include: timestamp, username, source IP, session ID, and outcome.


Troubleshooting

LDAP: "bind failed" error

Check credentials with ldapsearch first. If the command succeeds but IMTerm fails, verify LDAP_PASSWORD environment variable is set where IMTerm runs.

Kerberos: "KDC_ERR_S_PRINCIPAL_UNKNOWN"

The SPN is not registered. Run setspn -L corp\imterm-svc and verify the SPN matches the hostname in the browser URL exactly.

OIDC: redirect_uri mismatch

The redirect_url in config.yaml must exactly match the redirect URI registered in the IdP. Include the trailing / (or don't) consistently in both places.

SAML: assertion validation failure

Check system clocks. SAML assertions have a strict time window (+/- 5 minutes). If IMTerm's system time differs from the IdP's clock, assertions fail. Use NTP on both systems.


See also: IMTerm Admin Guide section 5 (Security), INTERNAL-LicenseAudit.md