SMSTunnel for Ory

Kratos and Ory Network SMS codes from your own phone

No code · Courier HTTP channel
kratos.courier.yml

A few lines of config, no code

Ory writes the text from its SMS templates (sign-in, verification and recovery codes) and its courier hands it to SMSTunnel over HTTP. Your own Android phone then sends it from its own number, so people get their code from a number they know.

Before you start

  1. 1. Install the SMSTunnel app from Google Play on your Android phone and sign in.
  2. 2. In your dashboard, open Apps → Add an app, pick Sign-in codes, name it (for example "Ory") and click Create the key.
  3. 3. Copy the key right away: it's shown only once. You can stop or delete the app there anytime, and Ory can't send texts anymore.

Get the steps with your key in them

It opens Add an app with Sign-in codes picked. Once the key is made, the dashboard shows every step and command with the key already filled in, ready to copy.

Keep the key in your platform's secrets, never in code that runs in the browser. Codes must be 4 to 10 digits: the default 6-digit codes are fine; codes with letters aren't accepted.

1. Add the courier channel

Merge this into your identity config, with your key in place of YOUR_SMSTUNNEL_API_KEY:

courier:
  channels:
    - id: sms
      type: http
      request_config:
        url: https://smstunnel.io/api/v1/sms/send-2fa
        method: POST
        body: base64://ZnVuY3Rpb24oY3R4KSB7CiAgdG86IGN0eC5yZWNpcGllbnQsCiAgbWVzc2FnZTogY3R4LmJvZHksCn0K
        headers:
          Content-Type: application/json
        auth:
          type: api_key
          config:
            name: X-API-Key
            value: YOUR_SMSTUNNEL_API_KEY
            in: header

The body is this Jsonnet, base64-encoded (self-hosted Kratos can also use file://…):

smstunnel-sms.jsonnet
function(ctx) {
  to: ctx.recipient,
  message: ctx.body,
}

Both files are in examples/ory. The config holds your key, so keep it out of public repositories.

2. Apply it

Ory Network

Download the identity config, add the block, and upload it again. You can also enter it in the Console's SMS configuration.

ory get identity-config --project <id> --workspace <id> --format yaml > identity-config.yaml
# add the courier block, then:
ory update identity-config --project <id> --workspace <id> --file identity-config.yaml

Self-hosted Kratos

Add the block to kratos.yml and run the courier: kratos serve --watch-courier or kratos courier watch.

3. Send codes by SMS

Your identity schema needs a phone trait with "via": "sms", for example "credentials": { "code": { "identifier": true, "via": "sms" } } for sign-in codes and "verification": { "via": "sms" } for verification. Ory has SMS templates for login_code, verification_code and recovery_code, and they include the code.

Worth knowing

  • Codes have their own allowance. They go through SMSTunnel's code endpoint, POST /api/v1/sms/send-2fa, which counts them apart from your other texts. See Pricing.
  • What counts as a code: 4 to 10 digits standing on their own, like 482913, or two groups of 3 digits, like 123-456. A text without one is refused. Details
  • One number per text, up to 320 characters.
  • 30 sends a minute. Past that, SMSTunnel answers 429 and asks to retry a little later.
  • Phone offline? The code waits and goes out as soon as the phone is back.

Build it with an AI assistant

Copy this prompt into Claude, ChatGPT, Cursor or Copilot and replace the part in [brackets]. Don't paste your API key into the chat: the prompt doesn't need it.

Help me send the SMS codes of Ory (Kratos self-hosted or Ory Network) from my own phone, with SMSTunnel.

About SMSTunnel (https://smstunnel.io): my own apps and tools hand text messages (SMS) to my SMSTunnel account, and my own Android phone sends them from my own number, on my own SIM and plan. The phone runs the SMSTunnel app from Google Play (https://play.google.com/store/apps/details?id=io.smstunnel.app), signed in to my account.

What I want: [describe what should send a text, to whom, and when]

How it works:
- No code needed: Ory's courier HTTP channel calls SMSTunnel directly. Merge this into the identity config:
courier:
  channels:
    - id: sms
      type: http
      request_config:
        url: https://smstunnel.io/api/v1/sms/send-2fa
        method: POST
        body: base64://ZnVuY3Rpb24oY3R4KSB7CiAgdG86IGN0eC5yZWNpcGllbnQsCiAgbWVzc2FnZTogY3R4LmJvZHksCn0K
        headers:
          Content-Type: application/json
        auth:
          type: api_key
          config:
            name: X-API-Key
            value: YOUR_SMSTUNNEL_API_KEY
            in: header
- The body is base64 of this Jsonnet (self-hosted Kratos can also use file://...):
function(ctx) {
  to: ctx.recipient,
  message: ctx.body,
}
- Ory Network: ory get identity-config --project <id> --workspace <id> --format yaml > identity-config.yaml, add the block, then ory update identity-config --project <id> --workspace <id> --file identity-config.yaml (or enter it in the Console's SMS configuration). Self-hosted Kratos: add the block to kratos.yml and run the courier (kratos serve --watch-courier or kratos courier watch).
- The identity schema needs a phone trait with "via": "sms", for example "credentials": { "code": { "identifier": true, "via": "sms" } } for sign-in codes and "verification": { "via": "sms" } for verification. Ory's SMS templates login_code, verification_code and recovery_code include the code.
- SMSTunnel's POST https://smstunnel.io/api/v1/sms/send-2fa takes {"to", "message"} with the header X-API-Key. The text must contain the code as 4 to 10 digits (Ory's codes are fine) and can be up to 320 characters; otherwise it answers 400 "No valid verification code found". Other answers: 401 bad key, 403 missing permission, 429 too many requests (30 a minute). If the phone is offline, the code waits and goes out when it is back.
- The API key comes from my SMSTunnel dashboard (https://dashboard.smstunnel.io): Apps → Add an app → Create the key. It is shown only once and can send texts and check whether they went out. The config file then holds the key, so keep it out of public repositories.

Rules for your answer:
- Do not ask for my SMSTunnel password or API key and do not put a real key in your answer; I will not paste it in this chat.
- Phone numbers must be in international format (+ and the country code).
- Help me test it with my own number first.
- Only send texts people expect from me. No unsolicited texts.

Ory is a trademark of its owner. SMSTunnel is a third-party integration and is not affiliated with, endorsed by, or sponsored by Ory.

Sign-in codes for other platforms

Another platform? sendCode() from the same package sends any code: see its README.

No phone paired yet?

Install the Android app and sign in with your account, and you're ready in about a minute.

Get it on Google Play