Radiator Server Documentation — v10.33.1

yubikey

YubiKey OTP offline authentication action

yubikey

Validates a Yubico OTP presented as a RADIUS PAP response by decrypting it locally using the AES-128 key stored in yubikey.secret. No network call is made; validation is fully offline.

This action is only for offline validation. If you use the yubikey HTTP backend for cloud validation, configure range on the backend block instead of this action.

The action extracts the public UID from the token identifier prefix and the 32-character modhex ciphertext, decrypts the OTP, and verifies the CRC16 checksum, private UID, and replay-protection counters.

Basic Syntax

YubiKey OTP is typically used as a second factor alongside a static password. The user enters their password and OTP concatenated in the PAP password field (<password><otp>), and the range parameter splits the field between the pap and yubikey actions:

@execute {
    backend {
        name "USERS";
        query "FIND_USER";
    }

    # Validate static password (everything except the last 44 characters)
    pap {
        range -44 0 exclusive;
    }

    # Validate YubiKey OTP (last 44 characters)
    yubikey {
        range -44 0;
    }
}

These examples omit the counter update step for brevity. See Replay Protection for the complete pattern including counter persistence.

For OTP-only authentication (single factor — possession only), omit range:

yubikey;

Parameters

range

Extracts a substring from the PAP response before passing it to the OTP validator. Use this when the user appends or prepends a static password to the OTP in the same PAP field.

Syntax: range <start> <end> [exclusive]

  • <start> - Starting index (negative values count from end)
  • <end> - Ending index (negative values count from end)
  • exclusive - Optional keyword; extracts everything except the specified range

A standard Yubico OTP is 44 characters (12-character modhex public UID + 32-character ciphertext).

Backend Mapping

The backend must populate yubikey context variables before the yubikey action runs. At minimum, yubikey.secret (the AES-128 key) is required. Optional variables enable public/private UID checks and replay detection.

For a complete backend schema, query examples, and counter update configuration, see Offline Validation Configuration in the YubiKey Authentication article.

Replay Protection

When yubikey.counter is set, the action compares the decrypted usage counter against the stored value:

  • Counter is lower than stored: rejected as replayed OTP.
  • Counter equals stored: session counter is compared; lower value is rejected.
  • Counter is higher than stored: accepted; both counters are updated in the context.

Persist the updated counters after successful authentication to prevent replay on the next request. See Offline Validation Configuration for the complete pipeline pattern.