Ephemeral Tokens

About Ephemeral Tokens

Ephemeral tokens are tokens issued by KAZOO with a payload of the creator’s choosing that can later be verified by another service and the payload retrieved. Use these tokens to create service integrations where KAZOO is used to validate and decrypt a provided token and the resulting payload is used by the service.

Schema

ephemeral token payloads

KeyDescriptionTypeDefaultRequiredSupport Level
claimsProvided claims from the client to encode in the tokenobject()true

Create an ephemeral token

Within the claims object, put whatever data you’d like encoded in the encrypted payload.

PUT /v2/accounts/{ACCOUNT_ID}/ephemeral_tokens

curl -v -X PUT \
    -H "X-Auth-Token: {API_TOKEN}" \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/ephemeral_tokens \
    -d '{"data":{"claims":{"secret":"data"}}}'
{"data":{"token":"{SHINY_JWT_TOKEN}"
        ,"id":"{TOKEN_ID}"
        }
 ,"timestamp":"{TIMESTAMP}"
 ,"version":"{VERSION}"
 ,"node":"{NODE}"
 ,"request_id":"{REQUEST_ID}"
 ,"status":"success"
 ,"tokens":{"consumed":1,"remaining":100}
 ,"auth_token":"{API_TOKEN}"
}

Fetch the claims of an ephemeral token

GET /v2/accounts/{ACCOUNT_ID}/ephemeral_tokens/{SHINY_JWT_TOKEN}

Returns the data encoded in the token along with some metadata.

The base payload returns will contain:

{"data":{
    "account_id":"{ACCOUNT_ID}"
    ,"exp":{UNIX_TIMESTAMP}
    ,"identity_sig":"{SIGNATURE}"
    ,"iss":"kazoo"
    ,"method":"cb_ephemeral_tokens"
    "id": "{TOKEN_ID}"
    ...
 }
}

There will also be SIP information:

    "SIP-Info":{
        "User-Agent":{
            "Realm":"{ACCOUNT_REALM}"
           ,"Username":"{SIP_USERNAME}"
        }
    }

The rest of the returned data object will be the data encoded in the creation of the token.

curl -v -X GET \
    -H "X-Auth-Token: {API_TOKEN}" \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/ephemeral_tokens/{SHINY_NEW_TOKEN}
{"data":{
  "account_id":"{ACCOUNT_ID}"
  ,"exp":{UNIX_TIMESTAMP}
  ,"identity_sig":"{SIGNATURE}"
  ,"iss":"kazoo"
  ,"method":"cb_ephemeral_tokens"
  ,"id":"{TOKEN_ID}"
  ,"secret":"data"
  ,"scope":"sip"
  ,"sub":"{SUB}"
 }
 ,"timestamp":"{TIMESTAMP}"
 ,"version":"{VERSION}"
 ,"node":"{NODE}"
 ,"request_id":"{REQUEST_ID}"
 ,"status":"success"
 ,"tokens":{"consumed":1,"remaining":100}
 ,"auth_token":"{API_TOKEN}"
}

SIP calls with Ephemeral tokens

Now that you have your shiny new token, you can register a SIP device over a WebRTC connection.

Use the token’s ID as your SIP username, the account’s SIP realm, and set the Authorization header to the token. The issued REGISTER packet should look something like this:

REGISTER sip:kamailio.server.com SIP/2.0
Via: SIP/2.0/UDP client.com:42400;branch=f320f2ba9fae
To: <sip:{TOKEN_ID}@{ACCOUNT_REALM}>
From: <sip:2db66f904c12a632111330640c07552f@{ACCOUNT_REALM}>;tag=60987672
Call-Id: {CALL_ID}
CSeq: 1 REGISTER
Max-Forwards: 70
Authorization: {SHINY_NEW_TOKEN}
Contact: <sip:{TOKEN_ID}@{ACCOUNT_REALM}>
Expires: 2600
User-Agent: libwebphone
Content-Length: 0

Note

This requires the jwt role to be installed and enabled on the Kamailio servers. Kamailio also must be >= 5.3.5

Callflows

To route calls to the ephemeral device, you need a callflow created with the ephemeral_device callflow action:

"flow":{
    "module":"ephemeral_device"
    ,"data":{
        "token_id":"{TOKEN_ID}"
        ,"dial_strategy":"simultaneous"
        ,"timeout":20
    }
}

Of course this could be served via Pivot callflow response or a channels API action. The settings of the callflow action mostly mirror the device action.

Device-based tokens

First and foremost, this method of authentication should only be used over secure connections (like WebRTC or SIPS) as the Authorization SIP header will contain that token that, if sniffed, could be used by other user agents (at least until it expires).

To generate tokens for authentication, the device needs to have the sip.method path set to authorization:

{
  "sip": {
    "method": "authorization"
  }
}

Generate an Authorization token for a device

curl -v -X PUT \
    -H "X-Auth-Token: {API_TOKEN}" \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/devices/{DEVICE_ID}/ephemeral_tokens \
    -d '{"data":{"claims":{"secret":"data"}}}'

{
  "auth_token": "{API_TOKEN}",
  "data": {
    "id": "{TOKEN_ID}",
    "token": "{AUTHZ_TOKEN}"
  },
  "node": "{NODE}",
  "request_id": "{REQUEST_ID}",
  "status": "success",
  "timestamp": "{TIMESTAMP}",
  "tokens": {
    "consumed": 1,
    "remaining": 100
  },
  "version": "{VSN}"
}

Decode your token

curl -v -X GET \
    -H "X-Auth-Token: {API_TOKEN} \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/ephemeral_tokens/{AUTHZ_TOKEN}

{
  "auth_token": "{API_TOKEN}",
  "data": {
    "secret": "data",
    "SIP-Info": {
      "Authorizing-ID": "{DEVICE_ID}",
      "User-Agent": {
        "Realm": "0060a2.sip.2600hz.com",
        "Username": "{TOKEN_ID}"
      }
    },
    "account_id": "{ACCOUNT_ID}",
    "exp": 1607923214,
    "id": "{TOKEN_ID}",
    "identity_sig": "{SIGNATURE}",
    "iss": "kazoo",
    "method": "cb_ephemeral_tokens",
    "scope": "sip",
    "sub": "{TOKEN_ID}@{ACCOUNT_ID}"
  },
  "node": "{NODE}",
  "request_id": "{REQUEST_ID}",
  "status": "success",
  "timestamp": "{TIMESTAMP}",
  "tokens": {
    "consumed": 1,
    "remaining": 100
  },
  "version": "{VSN}"
}

REGISTER your device

Using the {AUTHZ_TOKEN} value in your user agent’s Authorization header results in a SIP packet like:

REGISTER sip:{SIP_SERVER} SIP/2.0
Via: SIP/2.0/TCP {HOST}:48827;branch=768403aff237
To: <sip:{TOKEN_ID}@{SIP_REALM}>
From: <sip:{TOKEN_ID}@{SIP_REALM}>;tag=3328e732
Call-Id: {CALL_ID}
CSeq: 1 REGISTER
Max-Forwards: 70
Authorization: {AUTHZ_TOKEN}
Contact: <sip:{TOKEN_ID}@{SIP_REALM}>
Expires: 2600
Content-Length: 0

Caveats and notes

At present, Authorization headers for REGISTER packets will act like regular credentialed registration - one registration per device, with the most recent REGISTER taking precedence for calls to the device.

For outbound, authorization will be performed on the header if no registration is found. Thus any amount of outbound-only user agents can utilize a unique token generated for the device.

Currently token expiration is configured via system configs and defaults to one hour. User agents should be ready to fetch new tokens and re-register accordingly.

Requests

  • Routing information in the Req
  • Add DELETE to revoke the tokens

Use cases

Token-based user agents

Create a token with no associated device. Each token creates a unique registration to the user agent.

Engineering notes

The token’s “sub” will be {TokenId}@{AccountId} and SIP-Info.Username={TokenId}

Token-based devices

Create a device with sip.method = "authorization. Create a token based on that device ID, insert into the user agent’s Authorization header, and REGISTER (creating a registration for the device based on the token).

When you generate a new token for the device and REGISTER, the new token’s registration will replace the other token’s registration (just as if you re-registered a traditional SIP device).

Engineering notes

The token’s “sub” will be {DeviceId}@{AccountId} and SIP-Info.Username={TokenId}

Token-based meta devices

Create a “meta-device” device with sip.method = "authorization" and device_type="meta". Each token generated from that device ID can then be used by unique user agents (registrations by different tokens will not overwrite other tokens’ registration). Each user agent will use the settings of the “meta” device’s configuration as expected (caller ID, codec lists, etc) when making calls.

Engineering notes

The token’s “sub” will be {TokenId}@{AccountId} and SIP-Info:{Username={TokenId}, Endpoint-Meta-ID:{DeviceId}