Skip to content

Commit 176b49f

Browse files
cursoragentlovasoa
andcommitted
feat: Add sqlpage.hmac() function for secure signatures
Co-authored-by: contact <[email protected]>
1 parent 8bd0795 commit 176b49f

File tree

3 files changed

+89
-33
lines changed

3 files changed

+89
-33
lines changed

CHANGELOG.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,14 @@
11
# CHANGELOG.md
22

3+
## v0.38.0
4+
- Added a new `sqlpage.hmac()` function for cryptographic HMAC (Hash-based Message Authentication Code) operations.
5+
- Create and verify secure signatures for webhooks (Shopify, Stripe, GitHub, etc.)
6+
- Generate tamper-proof tokens for API authentication
7+
- Secure download links and temporary access codes
8+
- Supports SHA-256 (default) and SHA-512 algorithms
9+
- Returns hexadecimal string representation of HMAC
10+
- See the [function documentation](https://sql-page.com/functions.sql?function=hmac) for detailed examples
11+
312
## v0.37.1
413
- fixed decoding of UUID values
514
- Fixed handling of NULL values in `sqlpage.link`. They were encoded as the string `'null'` instead of being omitted from the link's parameters.

examples/official-site/sqlpage/migrations/67_hmac_function.sql

Lines changed: 66 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -10,63 +10,96 @@ VALUES (
1010
'hmac',
1111
'0.38.0',
1212
'shield-lock',
13-
'Computes the [HMAC](https://en.wikipedia.org/wiki/HMAC) (Hash-based Message Authentication Code) of the input data using a secret key and a cryptographic hash function.
13+
'Creates a unique "signature" for your data using a secret key. This signature proves that the data hasn''t been tampered with and comes from someone who knows the secret.
1414
15-
HMAC is used to verify both the data integrity and authenticity of a message. It is commonly used for:
16-
- Generating secure tokens and signatures
17-
- API request authentication
18-
- Webhook signature verification
19-
- Data integrity validation
15+
Think of it like a wax seal on a letter - only someone with the right seal (your secret key) can create it, and if someone changes the letter, the seal won''t match anymore.
2016
21-
### Example
17+
### What is HMAC used for?
2218
23-
#### Generate an HMAC for API authentication
19+
**HMAC** (Hash-based Message Authentication Code) is commonly used to:
20+
- **Verify webhooks**: Check that notifications from services like Shopify, Stripe, or GitHub are genuine
21+
- **Secure API requests**: Prove that an API request comes from an authorized source
22+
- **Generate secure tokens**: Create temporary access codes for downloads or password resets
23+
- **Protect data**: Ensure data hasn''t been modified during transmission
2424
25-
```sql
26-
-- Generate a secure signature for an API request
27-
SELECT sqlpage.hmac(
28-
''user_id=123&action=update'',
29-
''my-secret-api-key'',
30-
''sha256''
31-
) as request_signature;
32-
```
25+
### How to use it
3326
34-
#### Verify a webhook signature
27+
The `sqlpage.hmac` function takes three inputs:
28+
1. **Your data** - The text you want to sign (like a message or request body)
29+
2. **Your secret key** - A password only you know (keep this safe!)
30+
3. **Algorithm** (optional) - Either `sha256` (default) or `sha512`
31+
32+
It returns a long string of letters and numbers (the signature). If someone changes even one letter in your data, the signature will be completely different.
33+
34+
### Example 1: Verify Shopify Webhooks
35+
36+
When Shopify sends you a webhook (like when someone places an order), it includes a signature. Here''s how to verify it''s really from Shopify:
3537
3638
```sql
37-
-- Verify that a webhook request is authentic
39+
-- Shopify includes the signature in the X-Shopify-Hmac-SHA256 header
40+
-- and sends the webhook data in the request body
41+
42+
SELECT ''text'' as component,
43+
CASE
44+
WHEN sqlpage.hmac(
45+
sqlpage.request_body(),
46+
sqlpage.environment_variable(''SHOPIFY_WEBHOOK_SECRET''),
47+
''sha256''
48+
) = sqlpage.header(''X-Shopify-Hmac-SHA256'')
49+
THEN ''✅ Webhook verified! This is really from Shopify.''
50+
ELSE ''❌ Invalid signature - this might be fake!''
51+
END as contents;
52+
53+
-- If verified, process the order:
54+
INSERT INTO orders (order_data, received_at)
3855
SELECT
39-
CASE
40-
WHEN sqlpage.hmac(sqlpage.request_body(), ''webhook-secret'', ''sha256'') = :signature
41-
THEN ''Valid webhook''
42-
ELSE ''Invalid signature''
43-
END as status;
56+
sqlpage.request_body(),
57+
datetime(''now'')
58+
WHERE sqlpage.hmac(
59+
sqlpage.request_body(),
60+
sqlpage.environment_variable(''SHOPIFY_WEBHOOK_SECRET''),
61+
''sha256''
62+
) = sqlpage.header(''X-Shopify-Hmac-SHA256'');
4463
```
4564
46-
#### Create a secure download token
65+
### Example 2: Create Secure Download Links
66+
67+
Generate a token that expires after 1 hour:
4768
4869
```sql
49-
-- Generate a time-limited download token
70+
-- Create a download token
5071
INSERT INTO download_tokens (file_id, token, expires_at)
5172
VALUES (
5273
:file_id,
5374
sqlpage.hmac(
5475
:file_id || ''|'' || datetime(''now'', ''+1 hour''),
55-
sqlpage.environment_variable(''SECRET_KEY''),
76+
sqlpage.environment_variable(''DOWNLOAD_SECRET''),
5677
''sha256''
5778
),
5879
datetime(''now'', ''+1 hour'')
5980
);
6081
```
6182
62-
### Notes
83+
### Example 3: Sign API Requests
84+
85+
Prove your API request is authentic:
86+
87+
```sql
88+
-- Create a signature for your API call
89+
SELECT sqlpage.hmac(
90+
''user_id=123&action=update&timestamp='' || strftime(''%s'', ''now''),
91+
''my-secret-api-key'',
92+
''sha256''
93+
) as api_signature;
94+
```
95+
96+
### Important Security Tips
6397
64-
- The function returns a hexadecimal string representation of the HMAC.
65-
- If either `data` or `key` is NULL, the function returns NULL.
66-
- The `algorithm` parameter is optional and defaults to `sha256` if not specified.
67-
- Supported algorithms: `sha256`, `sha512`.
68-
- The key can be of any length. For maximum security, use a key that is at least as long as the hash output (32 bytes for SHA-256, 64 bytes for SHA-512).
69-
- Keep your secret keys secure and never expose them in client-side code or version control.
98+
- **Keep your secret key safe**: Store it in environment variables using `sqlpage.environment_variable()`, never hardcode it in your SQL files
99+
- **Use strong keys**: Your secret should be long and random (at least 32 characters)
100+
- **The signature is case-sensitive**: Even one wrong letter means the signature won''t match
101+
- **Algorithms**: Use `sha256` for most cases (it''s the default), or `sha512` for extra security
102+
- **NULL handling**: If your data or key is NULL, the function returns NULL
70103
'
71104
);
72105

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
-- Test Shopify webhook HMAC validation
2+
-- Shopify sends webhook body and HMAC signature in X-Shopify-Hmac-SHA256 header
3+
4+
SELECT 'text' as component,
5+
CASE
6+
-- Example webhook data and signature (simulating Shopify webhook)
7+
WHEN sqlpage.hmac(
8+
'{"id":1234567890,"email":"[email protected]","total_price":"123.45"}',
9+
'test-webhook-secret',
10+
'sha256'
11+
) = '40dc8e6d394a6ccc76a8394f17f64e65c06a8393a03e0fb6a24cb7ce575cd06c'
12+
THEN 'It works ! Shopify webhook signature verified'
13+
ELSE 'Signature mismatch: ' || sqlpage.hmac('{"id":1234567890,"email":"[email protected]","total_price":"123.45"}', 'test-webhook-secret', 'sha256')
14+
END as contents;

0 commit comments

Comments
 (0)