Security

Authentication

API keys for the SMS API, OpenID Connect for verification and messaging — and why a perfectly valid token can still be refused.

The APIs deliberately use different schemes, because they serve different kinds of consumer.

SMS Messaging APINumber Verification & Messaging APIs
SchemeAPI keyOpenID Connect
Credentialapikey headerAuthorization: Bearer
SuitsPartner and application clientsService-to-service
Authorizationverify:manage / messaging:send scope
StateStateless key checkStateful — validated on every request

Requests without valid credentials are rejected before they reach the service behind the API, so an unauthenticated call never touches your account's traffic.

API key — SMS Messaging

Keys are self-service. Sign up, create an application under My apps, then Register it against the SMS Messaging API. Your key is issued instantly and accepted straight away — it is shown once, so copy it then.

Registration is auto-approved in this environment, so there is no waiting.

Send the key in the apikey header:

curl -s -X POST https://api.kongapj.com/sms/v1/messages \
  -H "apikey: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"to":"+61400000000","from":"Optus","message":"Hi"}'

Your key is used only to authenticate the request and is never passed on to the service behind the API, so your credential stays private.

OpenID Connect — Verification & Messaging

These APIs use standard OAuth 2.0 access tokens. The Optus token endpoint is:

https://keycloak.kongapj.com/realms/optus/protocol/openid-connect/token

Request a token with the client credentials grant. A single machine-to-machine client is used, and the scope you ask for decides which API you can reach:

curl -s https://keycloak.kongapj.com/realms/optus/protocol/openid-connect/token \
  -d grant_type=client_credentials \
  -d client_id=optus-verify-demo \
  -d client_secret=optus-verify-secret \
  -d "scope=openid verify:manage" \
  | jq -r .access_token

Swap scope=openid verify:manage for scope=openid messaging:send to call the Messaging API.

Every request is checked for a valid signature, issuer and expiry, and the token must also carry the right scope.

This flow is stateful

Access tokens are validated on every request, with low-latency verification so there is no repeated round-trip cost. Revoking a token takes effect immediately across the platform, and the validated session is what makes verification a coherent, multi-step exchange rather than a series of unrelated calls.

Using an API client (Insomnia, Postman, Bruno)

Choose the Client Credentials grant, not Authorization Code:

FieldValue
Grant typeClient Credentials
Access Token URLhttps://keycloak.kongapj.com/realms/optus/protocol/openid-connect/token
Client IDoptus-verify-demo
Client Secretoptus-verify-secret
Scopeverify:manage or messaging:send

Request only the scope for the API you intend to call. A token minted with verify:manage will not open the Messaging API, and vice versa.

Authentication is not authorization

This is the distinction worth understanding. A token can be perfectly valid and still be refused:

SituationResponse
No token401 Unauthorized
Malformed or expired token401 Unauthorized
Valid token, missing the required scope403 Forbidden
Valid token with the required scope200 OK

You can see the 401 by calling without a token:

curl -i -X POST https://api.kongapj.com/verify/v1/verifications \
  -H "Content-Type: application/json" \
  -d '{"to":"+61400000000","channel":"sms"}'
# HTTP/1.1 401 Unauthorized

And the 403 by presenting a token that authenticates but lacks the scope the endpoint requires — for example a messaging:send token against the Verification API:

TOKEN=$(curl -s https://keycloak.kongapj.com/realms/optus/protocol/openid-connect/token \
  -d grant_type=client_credentials \
  -d client_id=optus-verify-demo \
  -d client_secret=optus-verify-secret \
  -d "scope=openid messaging:send" \
  | jq -r .access_token)

curl -i -X POST https://api.kongapj.com/verify/v1/verifications \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"to":"+61400000000","channel":"sms"}'
# HTTP/1.1 403 Forbidden

401 means "I do not know who you are". 403 means "I know exactly who you are, and you may not do this".


Sandbox credentials. The keys and client secrets on this page are throwaway values for the sandbox environment. In production, credentials are issued per application and kept private to your account — never shared or hard-coded like the sandbox examples above.