Cylinder JWT Authentication
Summary
Cylinder JWT authorization for Splinter’s REST APIs provides secure authentication for non-browser and non-user Splinter clients. This authentication method will be used by the Splinter CLIs and integration components.
Motivation
Splinter’s REST API provides routes for the Admin Service, Scabbard, Biome, and other Splinter components. Because it is desirable that the REST API be accessible to a variety of applications, it is important to have a robust authentication and authorization system implemented. While OAuth2 support provides standards-based authentication for browser applications, Cylinder JWT support will enable non-user and non-browser clients to easily authenticate with the REST API.
Cylinder JWTs are convenient because Cylinder is already an important part of the Splinter ecosystem; it is the library used to sign and verify signatures by the Splinter daemon itself as well as the Splinter CLIs. This makes it a prime candidate for REST API authentication. Additionally, Cylinder JWTs require no logins, handshakes, or other setup processes. They are self-signed and independently verifiable, which makes them both versatile and easy-to-use.
Guide-level explanation
The Cylinder library provides all the tools necessary to create and verify Cylinder JWTs.
Creating a Cylinder JWT
Splinter clients will create JWTs with the following steps:
- Load a Cylinder
PrivateKey
from the filesystem or another source - Initialize a signing
Context
(such as the Secp256k1 context) that matches the context used by the Splinter REST API - Create a
Signer
using the private key and context - Initialize a
JsonWebTokenBuilder
- Build and sign the JWT using the
Signer
The output of this process is a Cylinder JWT signed by the private key. This JWT
can then be used in any request to the Splinter REST API by providing it in the
Authorization
HTTP header in the format: Authorization: Bearer
Cylinder:<jwt>
.
Verifying a Cylinder JWT
The Splinter REST API will verify the Cylinder JWT and extract the signer’s public key through the following process:
- Parse the Cylinder JWT from the
Authorization
header when theBearer Cylinder:
prefix is present - Initialize a signing
Context
for the same algorithm used to sign the JWT - Create a signature
Verifier
using the context - Initialize a
JsonWebTokenParser
- Use the parser to parse the JWT and verify the signature
- Get the
issuer
from the parsed/verified JWT, which is the public key of the JWT signer
The public key is then used as the client’s identity throughout the Splinter REST API’s authorization system.
Reference-level explanation
Cylinder JWT Format
Cylinder JWTs are a custom implementation of the JWT standard. At a minimum all Cylinder JWTs contain the following data:
-
alg
header - the name of the algorithm used to sign the JWT. This is automatically set based on the type of signer used to sign the JWT. The splinterd REST API and its clients use thesecp256k1
algorithm. -
typ
header - the type of JWT. This is automatically set to the stringcylinder+jwt
by the JWT builder. -
iss
claim - the public key of the JWT’s signer, formatted as a hex string. This is automatically set by the JWT builder.
The JWT builder allows setting additional headers and claims, but these are not used by the Splinter REST API.
For more on the Cylinder JWT format, see the Cylinder JWT design.
Identity Provider
The Splinter REST API guards itself such that only properly authorized clients’ requests are accepted. This functionality is described in the REST API Authorization design.
An implementation of the IdentityProvider
trait (defined in the REST API
authorization design) will be added for authenticating clients that use Cylinder
JWTs. This implementation will be defined in the
splinter::rest_api::auth::identity::cylinder
module as the
CylinderKeyIdentityProvider
.
The CylinderKeyIdentityProvider
will require that the Authorization header
specified with REST API requests has the value Bearer Cylinder:<jwt>
, where
<jwt>
is a valid Cylinder JWT. The token type (Cylinder
) is required to
inform the Splinter REST API what type of token is being provided; this
differentiates Cylinder JWTs from the other authentication types supported by
Splinter (Biome and OAuth). If the token type is not provided or if the
authorization header is otherwise malformed, the Splinter REST API will respond
with 401 Unauthorized
.
This identity provider will use the JsonWebTokenParser
to verify the JWT and
extract the signer’s public key as described in the
Verifying a Cylinder JWT section of this document.
This identity provider will be configured for the REST API, which will call it for each request to get the client’s identity.
Configuration
To configure Cylinder JWT authentication for the Splinter REST API, the library
user will need to provide a Verifier
for verifying JWT signatures. This
verifier is created as described in the
Verifying a Cylinder JWT section of this document.
The Splinter daemon (splinterd) uses the secp256k1 algorithm and verifier, but
any algorithm can be used as long as there is a Verifier
implementation for
it.