# How I understand SNAP BI asymmetric signatures step by step

A beginner-friendly explanation of Bank Indonesia SNAP BI asymmetric signatures: what is signed, why SHA256withRSA is used, and how to test signing and verification safely.

- Date: 2026-09-27
- URL: https://ilham.dev/posts/how-to-understand-snap-bi-asymmetric-signature/
- Markdown: https://ilham.dev/posts/how-to-understand-snap-bi-asymmetric-signature/index.md
- Tags: snap-bi, signature, api, security, tools
- Reading time: 6 min


SNAP BI signatures can feel confusing because they combine several ideas at once:

- HTTP method;
- URL path;
- request body hash;
- timestamp;
- RSA private and public keys;
- a signature header.

When all of those appear together, it is easy to get lost. The
[SNAP BI Asymmetric Signature](/tools/snap-signature/) tool is useful because it
shows the signing input and lets you sign or verify it step by step.

This post explains the idea in plain language first, then walks through the testing
flow.

## The simple idea

A signature is a way to prove two things:

1. the request was created by someone holding the private key;
2. the important request data was not changed after signing.

In SNAP BI asymmetric signing, the client signs a prepared text using an RSA private
key. The receiver verifies the signature using the matching public key.

Simple mental model:

```text
private key = used to sign
public key  = used to verify
```

Do not share the private key. The public key is the one you give to the other side
for verification.

## What “asymmetric” means

“Asymmetric” means signing and verifying use different keys.

With HMAC, both sides share the same secret. With asymmetric signing, the signer
keeps the private key, and the verifier uses the public key.

That is useful for API integrations because the verifier does not need to know the
private key. If the public key verifies the signature, the request must have been
signed by the matching private key.

## What SHA256withRSA means

`SHA256withRSA` sounds complicated, but it can be read in two parts:

1. hash the signing text with SHA-256;
2. sign that hash with an RSA private key.

The signature is usually sent as Base64 text so it can fit safely inside an HTTP
header.

You do not need to manually do every cryptographic step. The important part is that
both sides must build the exact same signing text before signing or verifying.

## Step 1: collect the request parts

Before signing, write down the request details.

Example:

```text
HTTP method: POST
Path: /snap/v1.0/transfer-va/payment
Timestamp: 2026-09-27T10:00:00+07:00
```

Then prepare the request body:

```json
{
  "partnerReferenceNo": "INV-1001",
  "amount": {
    "value": "10000.00",
    "currency": "IDR"
  }
}
```

Be careful with the path. Usually the signing input expects the path and query, not
the full domain. For example:

```text
/snap/v1.0/transfer-va/payment
```

not:

```text
https://api.example.com/snap/v1.0/transfer-va/payment
```

Always follow the exact integration spec you are implementing.

## Step 2: understand the body hash

Many SNAP BI signature flows include a hash of the request body.

The purpose is simple:

> If the body changes, the body hash changes. If the hash changes, the signature no
> longer matches.

This protects the body from being silently modified.

A common problem is hashing a different body than the one actually sent.

For example, these two JSON bodies mean the same thing to a JSON parser, but they
are different text:

```json
{"amount":10000}
```

```json
{
  "amount": 10000
}
```

Depending on the required canonicalization rules, whitespace and formatting may
matter before hashing. The safest habit is to sign exactly the body string you will
send.

## Step 3: build the string to sign

The string to sign is the exact text that will be signed by the private key.

It usually combines values such as:

- HTTP method;
- endpoint path;
- body hash;
- timestamp.

The exact format must match the SNAP BI requirement for the endpoint and signature
type you are using.

This is where the [SNAP BI Asymmetric Signature](/tools/snap-signature/) tool helps:
it shows the signing input so you can see what is actually being signed.

If signing fails between systems, compare the string to sign on both sides first.
Most bugs are not caused by RSA itself. They are caused by different signing text.

## Step 4: paste the private key for signing

To create a signature, you need the RSA private key.

It may look like this:

```text
-----BEGIN PRIVATE KEY-----
...
-----END PRIVATE KEY-----
```

or sometimes:

```text
-----BEGIN RSA PRIVATE KEY-----
...
-----END RSA PRIVATE KEY-----
```

Use a test key while learning. Do not paste production private keys into tools you
do not control. The tool on this site runs in the browser, but the safe professional
habit is still to test with non-production keys whenever possible.

## Step 5: generate the signature

After the request parts and private key are filled in, generate the signature.

The result is usually Base64 text. It is meant to be sent in the required signature
header, according to the API spec.

At this point, save these for debugging:

- HTTP method;
- path;
- timestamp;
- body exactly as sent;
- body hash;
- string to sign;
- generated signature.

If the other system says the signature is invalid, those values are what you compare.

## Step 6: verify with the public key

Verification uses the public key that matches the private key.

A public key may look like this:

```text
-----BEGIN PUBLIC KEY-----
...
-----END PUBLIC KEY-----
```

Paste the public key, the same request parts, and the signature into the verification
side of the tool.

If verification passes, it means:

- the signature matches the signing input;
- the public key matches the private key used for signing;
- the signing text has not changed.

If verification fails, do not immediately blame the key. Check the signing text
first.

## Step 7: compare timestamps carefully

Timestamps are a common source of mistakes.

Check:

- timezone offset, such as `+07:00`;
- date format;
- seconds vs milliseconds;
- whether the timestamp in the header is exactly the timestamp used for signing;
- whether the receiver has a time tolerance window.

If the timestamp sent in the header differs from the timestamp used in the string to
sign, verification can fail.

## Step 8: compare paths carefully

Another common source of mistakes is the endpoint path.

These are different strings:

```text
/snap/v1.0/transfer-va/payment
/snap/v1.0/transfer-va/payment/
```

The trailing slash matters if it is included in the signing input.

Query strings can also matter:

```text
/snap/v1.0/report?from=2026-09-01&to=2026-09-27
```

If the spec says to include the query string, include it exactly. If it says not to,
do not include it.

## Step 9: compare request bodies carefully

If the body is part of the signature, compare the exact body string.

Common body-related mistakes:

- signing minified JSON but sending pretty JSON;
- signing pretty JSON but sending minified JSON;
- changing key order after signing;
- adding or removing whitespace;
- sending a different value type, such as number vs string;
- hashing an empty body when the request actually has a body.

For debugging, log a safe hash of the body instead of logging sensitive full payloads
in production.

## Step 10: use test keys before production keys

A safe workflow is:

1. generate or use test RSA keys;
2. sign a simple test request;
3. verify it locally with the public key;
4. send it to the sandbox environment;
5. compare the string to sign if sandbox rejects it;
6. only then move to production keys.

This prevents learning mistakes from touching production credentials.

## My SNAP BI signature checklist

When a SNAP BI signature fails, I check:

1. Is the HTTP method exactly the same?
2. Is the path exactly the same, including query string if required?
3. Is the body exactly the same as the body that was signed?
4. Is the body hash computed from the correct text?
5. Is the timestamp format correct?
6. Is the timestamp in the header the same as the timestamp in the signing input?
7. Was the signature created with the correct private key?
8. Is verification using the matching public key?
9. Is the signature Base64 copied without spaces or line breaks?
10. Are sandbox and production keys mixed up?

The professional way to debug this is not to guess. Compare the exact string to sign
on both sides. If that string is identical and the right keys are used, verification
should work.

The [SNAP BI Asymmetric Signature](/tools/snap-signature/) tool is useful because it
makes the hidden part visible: the text you are actually signing.
