Fastify plugin that adds an IndieAuth Token Endpoint to a Fastify server.
An IndieAuth Token Endpoint is responsible for generating and verifying OAuth 2.0 Bearer Tokens.
- Installation
- Token Endpoint Options
- Access tokens
- Refresh tokens
- User-provided functions
- Dependencies
- References
- License
npm install @jackdbd/fastify-token-endpoint
Options for the Fastify token-endpoint plugin
Properties
Name | Type | Description | Required |
---|---|---|---|
accessTokenExpiration (Token expiration) |
string |
Human-readable expiration time for the token issued by the token endpoint. Default: "15 minutes" Minimal Length: 1 |
no |
ajv | Instance of Ajv |
no | |
authorizationEndpoint (Authorization endpoint) |
string |
URL of the authorization server's authorization endpoint. Format: "uri" |
yes |
includeErrorDescription | boolean |
Whether to include an error_description property in all error responses. This is meant to assist the client developer in understanding the error. This is NOT meant to be shown to the end user.Default: false |
no |
isAccessTokenRevoked | Function |
Predicate function that returns true if a jti (JSON Web Token ID) is revoked. |
yes |
issuer | string |
The authorization server's issuer identifier. It's a URL that uses the "https" scheme and has no query or fragment components. It MUST also be a prefix of the indieauth-metadata URL. Format: "uri" |
yes |
jwks | object |
Private JSON Web Key Set (JWKS). The access token issued by this token endpoint will be signed using a JWK randomly chosen from this set. |
yes |
logPrefix | string |
Default: "token-endpoint " |
no |
onIssuedTokens | Function |
Handler invoked when the token endpoint has issued an access token and a refresh token. You should use this handler to persist the tokens to some storage (e.g. a database). |
yes |
refreshTokenExpiration (Token expiration) |
string |
Human-readable expiration time for the token issued by the token endpoint. Default: "30 days" Minimal Length: 1 |
no |
reportAllAjvErrors (report all AJV errors) |
boolean |
Whether to report all AJV validation errors. Default: false |
no |
retrieveRefreshToken | Function |
Function that retrieves a refresh token from a storage backend. |
yes |
revocationEndpoint (Revocation endpoint) |
string |
URL of the authorization server's OAuth 2.0 revocation endpoint. Format: "uri" |
yes |
userinfoEndpoint (Userinfo endpoint) |
string |
Format: "uri" |
yes |
Example
{
"accessTokenExpiration": "60 seconds",
"includeErrorDescription": false,
"jwks": {
"keys": [
{}
]
},
"logPrefix": "token-endpoint ",
"refreshTokenExpiration": "60 seconds",
"reportAllAjvErrors": false
}
Private JSON Web Key Set (JWKS). The access token issued by this token endpoint will be signed using a JWK randomly chosen from this set.
Properties
Name | Type | Description | Required |
---|---|---|---|
keys | object[] |
yes |
Example
{
"keys": [
{}
]
}
Items
Item Properties
Name | Type | Description | Required |
---|---|---|---|
alg | string |
Minimal Length: 1 |
no |
d | string |
Minimal Length: 1 |
no |
dp | string |
Minimal Length: 1 |
no |
dq | string |
Minimal Length: 1 |
no |
e | string |
Minimal Length: 1 |
no |
kid | string |
Minimal Length: 1 |
no |
kty | string |
Minimal Length: 1 |
yes |
n | string |
Minimal Length: 1 |
no |
p | string |
Minimal Length: 1 |
no |
q | string |
Minimal Length: 1 |
no |
qi | string |
Minimal Length: 1 |
no |
Example
[
{}
]
The access tokens issued by the token endpoint implemented by this plugin are JSON Web Tokens.
Each JWT issued by this token endpoint is signed with RS256 using a random JSON Web Key (JWK) from a given private JWK Set.
Each JWT issued by this token endpoint can be verified by anyone (for example by a revocation endpoint or an introspection endpoint) using the the kid
parameter from the matching public JWK Set.
[!WARNING] Since neither OAuth 2.0 nor IndieAuth require an access token to be implemented as a JSON Web Token, I am considering other implementations. Watch the talk Rethinking Authentication to learn more about possible alternative implementations for access tokens.
The refresh tokens issued by the token endpoint implemented by this plugin are Nano IDs generated with nanoid.
[!TIP] Read the article Why we chose NanoIDs for PlanetScale’s API for a comparison of Nano ID with UUIDs.
You need to implement the following asynchronous functions:
isAccessTokenRevoked
onIssuedTokens
retrieveRefreshToken
Predicate function that will be called to check whether a previously issued token is revoked or not.
Handler invoked when the token endpoint has issued an access token and a refresh token. You should use this handler to persist the tokens to some storage (e.g. a database).
The function accepts a single parameter, an object containing an access token, a refresh token, and few other properties about the issuer, the client application and the end-user.
Access token, refresh token, and some additional information about the issuer, the client, and the end-user.
Properties
Name | Type | Description | Required |
---|---|---|---|
access_token | string |
Minimal Length: 1 |
yes |
access_token_expires_in | number |
Minimum: 1 |
yes |
client_id | string |
The ID of the application that asks for authorization. An IndieAuth client ID is a URL. Format: "uri" |
yes |
issuer | string |
The authorization server's issuer identifier. It's a URL that uses the "https" scheme and has no query or fragment components. It MUST also be a prefix of the indieauth-metadata URL. Format: "uri" |
yes |
jti ("jti" (JWT ID) Claim) |
string |
Unique identifier for the JWT Minimal Length: 1 |
yes |
kid | string |
Minimal Length: 1 |
yes |
me (me (canonicalized)) |
string |
Profile URL (after URL Canonicalization) Format: "uri" |
yes |
redirect_uri | string |
Holds a URL. A successful response from this endpoint results in a redirect to this URL. Format: "uri" |
yes |
refresh_token | string |
Minimal Length: 1 |
yes |
refresh_token_expires_at ("exp" (Expiration Time) Claim) |
number |
UNIX timestamp when the JWT expires Minimum: 0 |
yes |
scope (OAuth 2.0 scope (scopes) claim) |
string |
Scope values. See RFC8693 scope claim Minimal Length: 1 |
yes |
Additional Properties: not allowed
Function that retrieves a refresh token from a storage backend.
Package | Version |
---|---|
@fastify/formbody | ^8.0.2 |
@fastify/response-validation | ^3.0.3 |
@jackdbd/indieauth | ^0.0.0-canary.1 |
@jackdbd/oauth2 | ^0.0.0-canary.1 |
@jackdbd/oauth2-error-responses | ^0.0.0-canary.1 |
@jackdbd/oauth2-tokens | ^0.0.0-canary.1 |
@jackdbd/schema-validators | ^0.0.0-canary.1 |
@sinclair/typebox | ^0.34.14 |
ajv | ^8.17.1 |
ajv-formats | ^3.0.1 |
fastify-plugin | ^5.0.1 |
⚠️ Peer DependenciesThis package defines 1 peer dependency.
Peer | Version range |
---|---|
fastify |
>=5.0.0 |
- Issuing an Access Token - The OAuth 2.0 Authorization Framework (RFC 6749)
- Refreshing an Access Token - The OAuth 2.0 Authorization Framework (RFC 6749)
- Access Token Response - IndieAuth
- IndieAuth Rocks! (validator for testing IndieAuth client and server implementations)
-
IndieAuth scopes:
email
,profile
-
Micropub scopes:
create
,update
,delete
,undelete
,draft
,media
© 2024 - 2025 Giacomo Debidda // MIT License