Stateless TURN REST API credentials (coturn-compatible shared secret).
What problem this solves
Signaling servers and Web backends need to mint time-limited TURN username/
password pairs without storing per-user secrets on the TURN server. The TURN
REST API pattern embeds expiry in the username and derives the password from
a shared HMAC key, matching coturn's use-auth-secret deployment model.
Usernames are "<expiry-unix>:<user-id>"; passwords are
Base64(HMAC-SHA1(secret, username)). Verification recomputes the HMAC and
rejects expired usernames before Allocate proceeds.
RFCs
Summary
Functions
Generates a time-limited REST username/password pair for user_id.
Returns true when username matches the <expiry>:<user-id> REST format.
Validates a REST username and returns the expected password on success.
Functions
@spec generate(String.t(), pos_integer(), binary()) :: {String.t(), String.t()}
Generates a time-limited REST username/password pair for user_id.
The username embeds the Unix expiry timestamp; the password is the
Base64-encoded HMAC-SHA1 of the username under secret.
Returns true when username matches the <expiry>:<user-id> REST format.
Examples
iex> Xirsys.XTurn.Auth.SharedSecret.rest_username?("1700000000:alice")
true
iex> Xirsys.XTurn.Auth.SharedSecret.rest_username?("alice")
false
Validates a REST username and returns the expected password on success.
Returns :expired when the embedded timestamp is in the past, or :error
when the username format is invalid.
Examples
iex> secret = "test-secret"
iex> {username, password} = Xirsys.XTurn.Auth.SharedSecret.generate("alice", 3600, secret)
iex> {:ok, ^password} = Xirsys.XTurn.Auth.SharedSecret.verify_username(username, secret)
iex> past = System.system_time(:second) - 10
iex> Xirsys.XTurn.Auth.SharedSecret.verify_username(to_string(past) <> ":bob", "secret")
:expired