-
Notifications
You must be signed in to change notification settings - Fork 2
SolarNet API authentication scheme Message Signatures
SolarNetwork accepts HTTP Message Signatures (RFC 9421) alongside the SNWS2 authentication scheme. Both use the same security token credentials: a token ID and a token secret. Security tokens work for both RFC 9421 and SNWS2 authentication simultaneously: you can freely switch between the two using the same token credentials.
This document specifies the profile of RFC 9421 required by SolarNetwork.
See https://go.solarnetwork.net/dev/api/ for a JavaScript client implementation of this authentication scheme designed to showcase how the API can be used.
The following table describes some terms used throughout this document.
| Term | Description |
|---|---|
tokenId |
The SolarUser generated token value. This is the value shown in the SolarUser token management screen. |
tokenSecret |
The SolarUser generated token secret. This value is shown only once in the SolarUser token management screen, when the token is first created. |
HMAC() |
A HMAC+SHA256 encoding function that accepts a secret key and message data as arguments, e.g. HMAC(key, message) and produces a 32-byte HMAC signed SHA256 digest |
RFC 9421 uses two HTTP headers to provide the signature SolarNetwork uses for authentication:
Signature-Input (defining what has been signed) and Signature (the actual signature).
SolarNetwork takes the Signature-Input headers and recomputes the signature based on what was
actually provided in the HTTP request. If the computed signature matches the one given in the
Signature header the request will be successfully authenticated as the token ID provided and
allowed to proceed.
Here is an example of what these headers look like:
Signature-Input: sn=("@method" "@authority" "@path" "@query");created=1789761471\
;keyid="MY-TOKEN-ID";tag="solarnetwork"
Signature: sn=:yt00kJV0rsRBmP7Pu7C8J2f+avzPAAzv1vEGX+SrCd8=:
SolarNetwork detects an RFC 9421 request by the presence of Signature-Input, as RFC 9421 appendix
A recommends. If a request carries an Authorization header naming a supported scheme,
that takes precedence.
The signature label (sn above) can be anything.
The following table outlines the signature parameters supported by SolarNetwork:
| Parameter | Required | Rule |
|---|---|---|
keyid |
yes | The token ID, optionally with a signing key date; see Signing keys |
created |
yes | Must be within the server's allowed date skew, which is 15 minutes |
expires |
no | If given, must not be in the past |
alg |
no | If given, must be hmac-sha256
|
nonce |
no | Accepted and ignored |
tag |
no | See Choosing a signature |
RFC 9421 lets the signer decide what message components of the HTTP request to cover (include) in its signature. SolarNetwork requires the following minimum set of items:
@method-
@authorityand@pathtogether, or@target-uri -
@query— required when the request has a query string -
content-digest— required when the request has content; see Request content -
content-type— required when the request includes this header - every
X-SN-*header the request includes
Any additional component may be covered. The sf, key, bs and name component parameters are
supported.
These are not supported and will be rejected:
- the
trparameter — trailer fields are not supported - the
reqparameter — not valid on a request signature (RFC 9421 §2.4) -
@status— applies to responses - the same component identifier covered more than once
The keyid parameter provides both the token ID and how its secret becomes the signing key. Both
forms are accepted; the derived key is the one SolarNetwork's own tooling uses by default, and the
one to prefer.
The signing key is derived from the token secret and a UTC date:
keyid="MY-TOKEN-ID:20260918"
→ K = HMAC(HMAC("SNWS3" + tokenSecret, "20260918"), "snws3_request")
This works the way an SNWS2 signing key does, and has the same benefit: the derived key
is only valid for 7 days from its date, so it can be given to whatever signs the request without
disclosing the token secret itself. The date must not be more than 6 days before, or 1 day after,
the UTC date of the created parameter.
The signing key is the UTF-8 encoded token secret:
keyid="MY-TOKEN-ID" → K = UTF8(tokenSecret)
Any RFC 9421 implementation can sign this way, with nothing but the token ID and secret and no knowledge of SolarNetwork's key derivation. That makes it the simplest way to get started, at the cost of handing the secret to the signer.
If the HTTP message includes body content, an RFC 9530 Content-Digest header
must be included, and treated as a covered message component.
SolarNetwork supports the sha-256 and sha-512 digest schemes, for example:
Content-Digest: sha-256=:X48E9qOokqqrvdts8nOJRJN3OWDUoyWxBf7kbu9DBPE=:
Note this is a different header than the RFC 3230 Digest field the SNWS2 scheme accepts. A
Content-Digest on the request is validated against the actual content whether or not it is covered
by the signature, and a request with content must cover it.
This includes application/x-www-form-urlencoded content. The SNWS2 scheme signs form parameters as
if they were query parameters; RFC 9421 does not so form content needs a Content-Digest like any
other content.
A request may carry more than one signature, for example when a proxy adds its own. To say
which one SolarNetwork should authenticate with, give it a tag parameter with the value
solarnetwork:
;tag="solarnetwork"
If no signature carries the tag and exactly one signature is present, that one is used. If no signature carries the tag and several are present, the request will be rejected.
A rejected request gets a 401 with the reason in the X-SN-ErrorMessage header, and an
Accept-Signature field describing what an acceptable signature must cover:
Accept-Signature: sn=("@method" "@authority" "@path" "@query");created;keyid\
;tag="solarnetwork"
For this request:
GET /solarquery/api/v1/sec/datum/stream/datum?nodeId=123&sourceId=meter HTTP/1.1
Host: localhost:9082
signed with token 12345678901234567890, secret lsdjfpse9jfoeijfe09j, at
created=1789761471 (2026-09-18 UTC), the signature base is:
"@method": GET
"@authority": localhost:9082
"@path": /solarquery/api/v1/sec/datum/stream/datum
"@query": ?nodeId=123&sourceId=meter
"@signature-params": ("@method" "@authority" "@path" "@query");created=1789761471\
;keyid="12345678901234567890:20260918";tag="solarnetwork"
and HMAC-SHA256 of that, keyed with the derived signing key
HMAC(HMAC("SNWS3lsdjfpse9jfoeijfe09j20260918"), "snws3_request"), gives:
Signature-Input: sn=("@method" "@authority" "@path" "@query");created=1789761471\
;keyid="12345678901234567890:20260918";tag="solarnetwork"
Signature: sn=:8gcZ/Rdd932qOF1Cm+hpu7M/hQQ92A3dCffFxtyTSWg=:
Signing the same request with the token secret directly — keyid of just
12345678901234567890 — gives
Signature: sn=:yt00kJV0rsRBmP7Pu7C8J2f+avzPAAzv1vEGX+SrCd8=: instead.
The API Explorer shows these steps for any request you give it, and generates a
matching curl command.
- SolarNetwork API access
- SolarNetwork API authentication
- SolarNetwork API rate limiting
- SolarNetwork global objects
- SolarNetwork aggregation
- SolarFlux API
- SolarIn API
- SolarQuery API
-
SolarUser API
- SolarUser enumerated types
- SolarUser datum expire API
- SolarUser datum export API
- SolarUser datum import API
- SolarUser datum stream alias API
- SolarUser event hook API
- SolarUser location request API
- SolarUser Cloud Integrations API
- SolarUser DIN API
- SolarUser DNP3 API
- SolarUser ININ API
- SolarUser OCPP API
- SolarUser OSCP API
- SolarUser Secrets API
- SolarUser SolarFlux API