
This page describes how to create [HTTPS API](/docs/https-api) tokens locally by signing them with your SSH private key. This can be done entirely offline and programmatically.

Alternatively, use [`ssh-key generate-api-key`](/docs/cli-ssh-key#ssh-key-generate-api-key) to have the server generate a token for you.

## Quick start

### Add a new SSH key to your exe.dev account

You don't _have_ to do this, but it's a good idea: you can revoke this API key by removing this ssh key from exe.dev, without disrupting your regular ssh access. The `-C` flag sets a name for this ssh key; feel free to change it.

```bash
ssh-keygen -t ed25519 -C api -f ~/.ssh/exe_dev_api
```

```bash
cat ~/.ssh/exe_dev_api.pub | ssh exe.dev ssh-key add
```

If you want finer-grained revocability of API keys, add more ssh keys.

### Generate a token using this ssh key

Permissions are specified as JSON. Each field overrides a default; see [Granular permissions](/docs/https-api#granular-permissions) for all available fields. We'll use `{}` for now; this creates a token that never expires.

Define a helper to convert base64 to base64url ([RFC 4648](https://datatracker.ietf.org/doc/html/rfc4648#section-5)).

```bash
b64url() { tr -d '\n=' | tr '+/' '-_'; }
```

Set the permissions and base64url-encode them.

```bash
export PERMISSIONS='{}'
```

```bash
export PAYLOAD=$(printf '%s' "$PERMISSIONS" | base64 | b64url)
```

Sign the permissions with your SSH key.

```bash
export SIG=$(printf '%s' "$PERMISSIONS" | ssh-keygen -Y sign -f ~/.ssh/exe_dev_api -n v0@exe.dev)
```

Strip the PEM armor and convert to base64url.

```bash
export SIGBLOB=$(echo "$SIG" | sed '1d;$d' | b64url)
```

Assemble the token.

```bash
export TOKEN="exe0.$PAYLOAD.$SIGBLOB"
```

### Test

Test the token by running a simple command.

```bash
curl -X POST https://exe.dev/exec -H "Authorization: Bearer $TOKEN" -d 'whoami'
```

## Shorter tokens

exe0 tokens are long and contain some information in plaintext.

If you want a short, opaque token, you may ask exe.dev to provide an exe1 token, which is nothing more than a handle for an exe0 token.

```bash
ssh exe.dev exe0-to-exe1 "$TOKEN"
```

This returns an exe1 token. The server validates the exe0 token before issuing an exe1 token. If the exe0 token is [for a particular VM](/docs/https-tokens-for-vms), you must specify that for the validation to succeed.

```bash
ssh exe.dev exe0-to-exe1 --vm=vm-name "$TOKEN"
```

exe1 tokens work everywhere exe0 tokens work, in exactly the same way.

An exe1 token is validated through its underlying exe0 token on every use. To revoke an exe1 token, revoke the underlying exe0 token.

## VM tokens via local signing

You can also create [VM-scoped tokens](/docs/https-tokens-for-vms) locally. The process is identical except the signing namespace changes from `v0@exe.dev` to `v0@VMNAME.exe.xyz`:

```bash
export SIG=$(printf '%s' "$PERMISSIONS" | ssh-keygen -Y sign -f ~/.ssh/exe_dev_api -n v0@myvm.exe.xyz)
```
