@schematize/client-credentials
v0.6.7
Published
Schematize Client Credentials Auth Library
Readme
@schematize/client-credentials
OAuth 2.0 client credentials grant for machine-to-machine use. Obtains an access token with client_id and client_secret, keeps bearer headers in memory, and skips redundant token requests while the token is still valid (with a short clock skew window).
Features
grant_type=client_credentialsvia POST withContent-Type: application/jsonbody (client_id,client_secret,scope, optionalresourcearray).- In-memory tokens only (no persistent storage in this library).
- Concurrent
authorize()calls collapse to one in-flight request viaauthorizing. - Node.js (
node:https) and browser (fetch); browsers log a console warning because embeddingclient_secretis unsafe.
Dependencies
@schematize/refs@schematize/metamodel
Installation
npm install @schematize/client-credentialsUsage (Node)
import ClientCredentials from '@schematize/client-credentials';
const auth = ClientCredentials({
endpoints: {
token: 'https://auth.example.com/token',
},
clientId: 'your-client-id',
clientSecret: process.env.CLIENT_SECRET,
scope: 'api:read api:write',
});
await auth.authorize();
const response = await fetch('https://api.example.com/data', {
headers: auth.headers,
});Configuration
endpoints.token(required): string URL of the token endpoint.clientId,clientSecret(required).scope: optional string passed in the JSON body.resources: optionalstring[]; when set, the JSON body includesresource: [...](must be an array).
There is no endpoints.revoke support in this package: signout only clears local state on the instance.
API
auth.initialized
Same promise as initialize(). Tokens are only in memory, so you typically await auth.authorize() first; you can still await auth.initialized for a consistent shape with other auth helpers.
await auth.initialized;initialize()
Resolves immediately; reserved for future automatic token lifecycle behavior. The constructor sets initialized to this promise.
await auth.initialize();authorize()
- If
accessTokenexists andexpires(milliseconds) is more than 20 seconds in the future, returnsPromise.resolve()(no return value). - Otherwise POSTs JSON to
endpoints.tokenand on success sets:authorized,accessToken,headers,expires=Date.now() + expires_in * 1000- clears
error,errorDescription,errorUri
- Returns a Promise that resolves to
thison success. authorizingexposes the in-flight promise while a request runs.
await auth.authorize();
const api = await fetch(`https://api.example.com/v1/resource`, {
headers: auth.headers,
});
// Token still valid: second call may resolve immediately without a network POST
await auth.authorize();
// Wait for another caller’s in-flight token request
if (auth.authorizing) {
await auth.authorizing;
}signout()
Clears authorized, accessToken, expires, headers, userInfo, and error fields. Does not call a revoke endpoint.
await auth.signout();
console.log(auth.authorized);getUserInfo()
Always throws: not applicable for client credentials.
try {
await auth.getUserInfo();
} catch (e) {
console.error(e.message);
}Properties
| Property | Notes |
| --- | --- |
| authorized | Boolean |
| accessToken | String when authorized |
| headers | { Authorization: 'Bearer …' } when authorized |
| expires | Milliseconds since epoch when the access token should be treated as expired |
| userInfo | Cleared on signout; not populated by this flow |
| error, errorDescription, errorUri | Set from token error JSON when present |
| authorizing | Promise while a token request is in flight, otherwise undefined |
| initialized | Promise from initialize() |
Security
In browsers the constructor logs:
auth.clientCredentials: You should NEVER use this in a browser environment.You will expose your 'clientSecret' to anyone who can inspect this code allowing anyone access.Keep client_secret on the server, use HTTPS for the token endpoint, and prefer environment-backed secrets in Node.
License
MIT
Author
Benjamin Bytheway
