Skip to content

Commit 8cc102f

Browse files
authored
Merge pull request #431 from smallstep/carl/radius-webhooks
RADIUS authentication webhooks
2 parents b07239e + 3ed7639 commit 8cc102f

File tree

2 files changed

+169
-1
lines changed

2 files changed

+169
-1
lines changed

manifest.json

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,8 +85,12 @@
8585
{
8686
"title": "Deploy EAP-TLS Wi-Fi with Intune",
8787
"path": "/tutorials/intune-mdm-setup-guide.mdx"
88+
},
89+
{
90+
"title": "Wi-Fi Authentication Webhooks",
91+
"path": "/tutorials/wifi-authentication-webhooks.mdx"
8892
}
89-
]
93+
]
9094
},
9195
{
9296
"title": "Smallstep for Certificate-Based VPN",
Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
---
2+
updated_at: September 08, 2025
3+
title: "Wi-Fi Authentication Webhooks"
4+
html_title: "Wi-Fi Authentication Webhooks"
5+
description: Smallstep's RADIUS server can call external webhooks for EAP-TLS authorization decisions.
6+
---
7+
8+
> This feature is available to Smallstep Enterprise RADIUS customers.
9+
10+
## Overview
11+
12+
With Wi-Fi authentication webhooks, you can integrate Smallstep’s RADIUS authentication workflow with your own device posture or authorization checks during EAP-TLS Wi-Fi connection requests. All you need is a webhook server that Smallstep can reach out to. Your webhook server will evaluate or log the presented client certificate, and return an authorization decision.
13+
14+
Smallstep can authenticate to your webhook server using a bearer token or HTTP basic authentication.
15+
16+
## Configuring a RADIUS Webhook in Smallstep
17+
18+
Our [customer support team](https://support.smallstep.com/kb-tickets/new) can configure a new RADIUS webhook for you.
19+
20+
## RADIUS Webhook specification
21+
22+
Your webhook server should use a TLS server certificate issued by a public Web PKI CA.
23+
24+
### Request format
25+
26+
Your webhook server should expect the following request format:
27+
28+
- Method: `POST`
29+
- Content-Type: `application/json`
30+
- Headers:
31+
- `X-Smallstep-Webhook-ID:` A UUID for the RADIUS webhook making the request
32+
- `X-Smallstep-Signature:` Hex‑encoded HMAC‑SHA256 of the raw request body using the webhook’s signing secret
33+
- `Authorization:` Optional. Either "Bearer <token>" or HTTP Basic auth, if configured.
34+
- Body (JSON):
35+
- `timestamp`: The RFC8222 timestamp of the request
36+
- `x509Certificate`: A JSON representation of the certificate that follows [this data structure](https://github.com/smallstep/crypto/blob/master/x509util/certificate.go#L17). Additionally, there is a `raw` field containing a base64-encoded DER representation of the client certificate.
37+
38+
Example request body:
39+
40+
```json
41+
{
42+
"timestamp": "2024-01-15T10:30:00Z",
43+
"x509Certificate": {
44+
"subject": {
45+
"country": ["US"],
46+
"organization": ["Example Corp"],
47+
"organizationalUnit": ["Engineering"],
48+
"locality": ["San Francisco"],
49+
"province": ["CA"],
50+
"streetAddress": ["123 Main St"],
51+
"postalCode": ["94105"],
52+
"serialNumber": "123456",
53+
"commonName": "[email protected]",
54+
"names": [
55+
{
56+
"type": "2.5.4.3",
57+
"value": "[email protected]"
58+
}
59+
],
60+
"extraNames": []
61+
},
62+
"issuer": {
63+
"country": ["US"],
64+
"organization": ["Example CA"],
65+
"organizationalUnit": ["CA Unit"],
66+
"locality": ["San Francisco"],
67+
"province": ["CA"],
68+
"streetAddress": ["456 CA St"],
69+
"postalCode": ["94105"],
70+
"serialNumber": "CA123",
71+
"commonName": "Example Root CA",
72+
"names": [],
73+
"extraNames": []
74+
},
75+
"serialNumber": "270390854734985720984572058347298347234",
76+
"sans": [
77+
{
78+
"type": "email",
79+
"value": "[email protected]"
80+
}
81+
],
82+
"emailAddresses": ["[email protected]"],
83+
"ipAddresses": [],
84+
"uris": [],
85+
"extensions": [],
86+
"keyUsage": ["digitalSignature", "keyEncipherment"],
87+
"extKeyUsage": ["serverAuth", "clientAuth"],
88+
"unknownExtKeyUsage": [],
89+
"subjectKeyId": "base64EncodedSKID==",
90+
"authorityKeyId": "base64EncodedAKID==",
91+
"ocspServer": ["http://ocsp.example.com"],
92+
"issuingCertificateURL": ["http://ca.example.com/ca.crt"],
93+
"dnsNames": ["example.com", "www.example.com"],
94+
"permittedDNSDomainsCritical": false,
95+
"permittedDNSDomains": [],
96+
"excludedDNSDomains": [],
97+
"permittedIPRanges": [],
98+
"excludedIPRanges": [],
99+
"permittedEmailAddresses": [],
100+
"excludedEmailAddresses": [],
101+
"permittedURIDomains": [],
102+
"excludedURIDomains": [],
103+
"crlDistributionPoints": ["http://crl.example.com/ca.crl"],
104+
"policyIdentifiers": [],
105+
"publicKey": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA...",
106+
"publicKeyAlgorithm": "RSA",
107+
"notBefore": "2024-01-01T00:00:00Z",
108+
"notAfter": "2025-01-01T00:00:00Z",
109+
"raw": "MIIDXTCCAkWgAwIBAgIJAKb..."
110+
}
111+
}
112+
```
113+
114+
### Signature verification
115+
116+
For signature verification, you will need the signing secret associated with `X-Smallstep-Webhook-ID`, which was given to you when your Smallstep support representative configured the webhook on your behalf. To verify the signature:
117+
118+
1. Compute HMAC‑SHA256 over the raw request body bytes
119+
2. Hex‑encode the result and compare to the `X-Smallstep-Signature:` request header value
120+
121+
### Response format
122+
123+
Your server should respond with the following:
124+
125+
- Content-Type: `application/json`
126+
- HTTP status codes:
127+
- `200`: Webhook processed successfully
128+
- Anything else: Authorization will be denied by RADIUS
129+
- Body (JSON):
130+
- `allow`: boolean. Should the Wi-Fi client authentication request be allowed?
131+
132+
Minimal success response:
133+
134+
```json
135+
{ "allow": true }
136+
```
137+
138+
- `error`: object (optional). If an error is passed, it will be visible in your Smallstep event log.
139+
140+
Deny with reason:
141+
142+
```json
143+
{
144+
"allow": false,
145+
"error": {
146+
"message": "Device non-compliant with posture check",
147+
"code": "E1002"
148+
}
149+
}
150+
```
151+
152+
153+
## Example Code
154+
155+
As a starting point for your implementation, Smallstep offers an [example RADIUS webhook server](https://github.com/smallstep/radius-webhooks/), written in Go.
156+
157+
## Operational guidance
158+
159+
- Multiple webhooks are supported. Webhooks are called after a client certificate is verified by Smallstep. They are called sequentially, but without any guarantee of order.
160+
- Timeouts (10 seconds) or non-`200` HTTP status codes result in a denial decision by Smallstep. Build for high availability and fast failover. Run at least two replicas behind a load balancer.
161+
- Smallstep may retry briefly if it receives a transient `5xx` HTTP status codes
162+
- Deny known‑bad cases using `"allow": false`; reserve non‑`200` HTTP status codes for unexpected failures. This will avoid incidental denies.
163+
- Store the signing secret securely. Rotate the secret by creating a new webhook, distributing its secret, then decommissioning the old one.
164+
- It is recommended that you log request IDs, the webhook ID, and your decision for auditing. If possible, avoid logging full certificates.

0 commit comments

Comments
 (0)