Authentication
Morph 1 app RSA2; morph 2 Access Key HMAC
OpenAPI authentication has two layers, stacked by app configuration.
Morph 1 — app RSA2 (always)
Every request must set sign using the app private key.
Canonical string
- Take all non-empty body fields
- Remove
signitself - Keep
sign_type=RSA2 - Sort keys lexicographically, join as
k1=v1&k2=v2&…
Sign
SHA256WithRSA (PKCS#1 v1.5) over that string, Base64-encode into sign.
Re-sign whenever the body changes. Keep the private key on your server only.
Morph 2 — Access Key HMAC (when enabled)
If the app requires Access Keys (access_key_required), payment methods must also send:
| Field | Meaning |
|---|---|
key_id | Access Key id |
key_sign | HMAC signature (Base64) |
Computing key_sign
mac_key = SHA-256( utf8(secret) ) // 32 bytes — do not HMAC with raw secret
content = sort_join(app_id, key_id, merchant_no, method, store_no, timestamp)
key_sign = Base64( HMAC-SHA256(mac_key, content) )sort_join: non-empty fields only, keys sorted, k=v joined with &. Do not include key_sign in content.
Exempt from morph 2
access.key.* (create / list / rotate / revoke) uses morph 1 only.
Managing keys must not require an Access Key (chicken-and-egg).
How the layers run
request
→ verify app RSA2 (reject on failure)
→ if app requires Access Key and method is not access.key.*
→ verify key_id / key_sign / binding / scope
→ business logicWithout the force flag, payments may use morph 1 only (early integration). Once forced, a missing key yields errors such as E07311. See Errors.