@commercelayer/js-auth
Advanced tools
Comparing version 6.0.0-beta.0 to 6.0.0-beta.1
@@ -41,3 +41,3 @@ interface TBaseOptions { | ||
} | ||
interface TBaseReturn { | ||
type TBaseReturn = { | ||
/** | ||
@@ -67,2 +67,4 @@ * The access token. | ||
createdAt: number; | ||
} & TError; | ||
interface TError { | ||
/** | ||
@@ -120,2 +122,29 @@ * The list of errors when something goes wrong. | ||
/** | ||
* Commerce Layer, through OAuth2, provides the support of token exchange in the on-behalf-of (delegation) scenario which allows, | ||
* for example, to make calls on behalf of a user and get an access token of the requesting user without direct user interaction. | ||
* Sales channels and webapps can accomplish it by leveraging the JWT Bearer flow, | ||
* which allows a client application to obtain an access token using a JSON Web Token (JWT) assertion. | ||
* @see https://docs.commercelayer.io/core/authentication/jwt-bearer | ||
*/ | ||
interface TJwtBearerOptions extends TBaseOptions { | ||
/** Your application's client secret. */ | ||
clientSecret: string; | ||
/** | ||
* A single JSON Web Token ([learn more](https://docs.commercelayer.io/core/authentication/jwt-bearer#creating-the-jwt-assertion)). | ||
* Max size is 4KB. | ||
* | ||
* **You can use the `createAssertion` helper method**. | ||
* | ||
* @example | ||
* ```ts | ||
* import { createAssertion } from '@commercelayer/js-auth' | ||
* ``` | ||
*/ | ||
assertion: string; | ||
} | ||
interface TJwtBearerReturn extends Omit<TPasswordReturn, 'ownerType'> { | ||
ownerType: 'user' | 'customer'; | ||
} | ||
/** | ||
* The refresh token grant type is used by clients to exchange a refresh token for an access token when the access token has expired. | ||
@@ -132,8 +161,17 @@ * @see https://docs.commercelayer.io/core/authentication/refresh-token | ||
*/ | ||
type GrantType = 'password' | 'refresh_token' | 'client_credentials' | 'authorization_code'; | ||
type AuthenticateOptions<TGrantType extends GrantType> = TGrantType extends 'password' ? TPasswordOptions : TGrantType extends 'refresh_token' ? TRefreshTokenOptions : TGrantType extends 'client_credentials' ? TClientCredentialsOptions : TGrantType extends 'authorization_code' ? TAuthorizationCodeOptions : never; | ||
type AuthenticateReturn<TGrantType extends GrantType> = TGrantType extends 'password' ? TPasswordReturn : TGrantType extends 'refresh_token' ? TPasswordReturn : TGrantType extends 'client_credentials' ? TBaseReturn : TGrantType extends 'authorization_code' ? TAuthorizationCodeReturn : never; | ||
type GrantType = 'password' | 'refresh_token' | 'client_credentials' | 'authorization_code' | 'urn:ietf:params:oauth:grant-type:jwt-bearer'; | ||
type AuthenticateOptions<TGrantType extends GrantType> = TGrantType extends 'urn:ietf:params:oauth:grant-type:jwt-bearer' ? TJwtBearerOptions : TGrantType extends 'password' ? TPasswordOptions : TGrantType extends 'refresh_token' ? TRefreshTokenOptions : TGrantType extends 'client_credentials' ? TClientCredentialsOptions : TGrantType extends 'authorization_code' ? TAuthorizationCodeOptions : never; | ||
type AuthenticateReturn<TGrantType extends GrantType> = TGrantType extends 'urn:ietf:params:oauth:grant-type:jwt-bearer' ? TJwtBearerReturn : TGrantType extends 'password' ? TPasswordReturn : TGrantType extends 'refresh_token' ? TPasswordReturn : TGrantType extends 'client_credentials' ? TBaseReturn : TGrantType extends 'authorization_code' ? TAuthorizationCodeReturn : never; | ||
type RevokeOptions = Pick<TBaseOptions, 'clientId' | 'domain'> & { | ||
/** Your application's client secret (required for confidential API credentials and non-confidential API credentials without a customer or a user in the JWT only). */ | ||
clientSecret?: string; | ||
/** A valid access or refresh token. */ | ||
token: string; | ||
}; | ||
type RevokeReturn = Pick<TError, 'errors'>; | ||
declare function authenticate<G extends GrantType>(grantType: G, { domain, headers, ...options }: AuthenticateOptions<G>): Promise<AuthenticateReturn<G>>; | ||
declare function revoke({ domain, ...options }: RevokeOptions): Promise<RevokeReturn>; | ||
/** | ||
@@ -254,2 +292,48 @@ * Decode a Commerce Layer access token. | ||
export { type AuthenticateOptions, type AuthenticateReturn, type GrantType, authenticate, jwtDecode, jwtIsDashboard, jwtIsIntegration, jwtIsSalesChannel, jwtIsUser, jwtIsWebApp }; | ||
interface Owner { | ||
type: 'User' | 'Customer'; | ||
id: string; | ||
} | ||
/** | ||
* Create a JWT assertion as the first step of the [JWT bearer token authorization grant flow](https://docs.commercelayer.io/core/authentication/jwt-bearer). | ||
* | ||
* The JWT assertion is a digitally signed JSON object containing information | ||
* about the client and the user on whose behalf the access token is being requested. | ||
* | ||
* This JWT assertion can include information such as the issuer (typically the client), | ||
* the owner (the user on whose behalf the request is made), and any other relevant claims. | ||
* | ||
* @example | ||
* ```ts | ||
* const assertion = await createAssertion({ | ||
* payload: { | ||
* 'https://commercelayer.io/claims': { | ||
* owner: { | ||
* type: 'Customer', | ||
* id: '4tepftJsT2' | ||
* }, | ||
* custom_claim: { | ||
* customer: { | ||
* first_name: 'John', | ||
* last_name: 'Doe' | ||
* } | ||
* } | ||
* } | ||
* } | ||
* }) | ||
* ``` | ||
*/ | ||
declare function createAssertion({ payload }: Assertion): Promise<string>; | ||
interface Assertion { | ||
/** Assertion payload. */ | ||
payload: { | ||
'https://commercelayer.io/claims': { | ||
/** The customer or user you want to make the calls on behalf of. */ | ||
owner: Owner; | ||
/** Any other information (key/value pairs) you want to enrich the token with. */ | ||
custom_claim?: Record<string, unknown>; | ||
}; | ||
}; | ||
} | ||
export { type AuthenticateOptions, type AuthenticateReturn, type GrantType, type RevokeOptions, type RevokeReturn, authenticate, createAssertion, jwtDecode, jwtIsDashboard, jwtIsIntegration, jwtIsSalesChannel, jwtIsUser, jwtIsWebApp, revoke }; |
@@ -1,2 +0,2 @@ | ||
function o(e){return e.replace(/[A-Z]/g,function(n){return"_"+n.toLowerCase()})}function i(e,n){return Object.keys(e).reduce((t,a)=>{let r=n(a);return t[r]=e[a],t},{})}function p(e){return e.replace(/([-_][a-z])/g,n=>n.toUpperCase().replace("-","").replace("_",""))}async function c(e,{domain:n="commercelayer.io",headers:t,...a}){let r=i({grant_type:e,...a},o),s=await(await fetch(`https://auth.${n}/oauth/token`,{method:"POST",headers:{"Content-Type":"application/json",Accept:"application/json",...t},body:JSON.stringify(r)})).json();return s.expires=new Date(Date.now()+s.expires_in*1e3),i(s,p)}function d(e){let[n,t]=e.split(".");return{header:JSON.parse(n!=null?l(n):"null"),payload:JSON.parse(t!=null?l(t):"null")}}function l(e){return typeof window<"u"?window.atob(e):Buffer.from(e,"base64").toString("binary")}function u(e){return e.application.kind==="user"}function g(e){return e.application.kind==="dashboard"}function y(e){return e.application.kind==="integration"}function C(e){return e.application.kind==="sales_channel"}function T(e){return e.application.kind==="webapp"}export{c as authenticate,d as jwtDecode,g as jwtIsDashboard,y as jwtIsIntegration,C as jwtIsSalesChannel,u as jwtIsUser,T as jwtIsWebApp}; | ||
function p(e){return e.replace(/[A-Z]/g,function(n){return"_"+n.toLowerCase()})}function i(e,n){return Object.keys(e).reduce((t,a)=>{let r=n(a);return t[r]=e[a],t},{})}function d(e){return e.replace(/([-_][a-z])/g,n=>n.toUpperCase().replace("-","").replace("_",""))}async function u(e,{domain:n="commercelayer.io",headers:t,...a}){let r=i({grant_type:e,...a},p),s=await(await fetch(`https://auth.${n}/oauth/token`,{method:"POST",headers:{"Content-Type":"application/json",Accept:"application/json",...t},body:JSON.stringify(r)})).json();return s.expires=new Date(Date.now()+s.expires_in*1e3),i(s,d)}async function g({domain:e="commercelayer.io",...n}){let t=i(n,p);return await(await fetch(`https://auth.${e}/oauth/revoke`,{method:"POST",headers:{"Content-Type":"application/json",Accept:"application/json"},body:JSON.stringify(t)})).json()}function c(e){return typeof window<"u"?window.btoa(e.replaceAll("=","").replaceAll("+","-").replaceAll("/","_")):Buffer.from(e,"binary").toString("base64url")}function l(e){return typeof window<"u"?window.atob(e.replaceAll("-","+").replaceAll("_","/")):Buffer.from(e,"base64url").toString("binary")}function m(e){let[n,t]=e.split(".");return{header:JSON.parse(n!=null?l(n):"null"),payload:JSON.parse(t!=null?l(t):"null")}}function y(e){return e.application.kind==="user"}function f(e){return e.application.kind==="dashboard"}function C(e){return e.application.kind==="integration"}function T(e){return e.application.kind==="sales_channel"}function w(e){return e.application.kind==="webapp"}async function k({payload:e}){return await h(e,"cl")}async function h(e,n){let a=c(JSON.stringify({alg:"HS512",typ:"JWT"})),r=c(JSON.stringify({...e,iat:Math.floor(new Date().getTime()/1e3)})),o=`${a}.${r}`,s=await S(o,n);return`${o}.${s}`}async function S(e,n){let t=new TextEncoder,a={name:"HMAC",hash:"SHA-512"},r=await crypto.subtle.importKey("raw",t.encode(n),a,!1,["sign","verify"]),o=await crypto.subtle.sign(a.name,r,t.encode(e));return c(String.fromCharCode(...new Uint8Array(o)))}export{u as authenticate,k as createAssertion,m as jwtDecode,f as jwtIsDashboard,C as jwtIsIntegration,T as jwtIsSalesChannel,y as jwtIsUser,w as jwtIsWebApp,g as revoke}; | ||
//# sourceMappingURL=index.js.map |
{ | ||
"name": "@commercelayer/js-auth", | ||
"version": "6.0.0-beta.0", | ||
"version": "6.0.0-beta.1", | ||
"description": "Commerce Layer Javascript Auth", | ||
@@ -39,3 +39,5 @@ "repository": { | ||
"devDependencies": { | ||
"@types/jsonwebtoken": "^9.0.6", | ||
"@types/node": "^20.11.27", | ||
"jsonwebtoken": "^9.0.2", | ||
"tsup": "^8.0.2", | ||
@@ -53,4 +55,5 @@ "typescript": "^5.4.2", | ||
"test": "pnpm run lint && vitest run --silent", | ||
"test:watch": "vitest --silent", | ||
"build": "tsup" | ||
} | ||
} |
@@ -20,2 +20,4 @@ # Commerce Layer JS Auth | ||
- [Provisioning application](#provisioning) | ||
- [JWT bearer](#jwt-bearer) | ||
- [Revoking a token](#revoking-a-token) | ||
- [Utilities](#utilities) | ||
@@ -209,2 +211,60 @@ - [Decode an access token](#decode-an-access-token) | ||
### JWT bearer | ||
Commerce Layer, through OAuth2, provides the support of token exchange in the _on-behalf-of_ (delegation) scenario which allows, | ||
for example, to make calls on behalf of a user and get an access token of the requesting user without direct user interaction. | ||
**Sales channels** and **webapps** can accomplish it by leveraging the [JWT Bearer flow](https://docs.commercelayer.io/core/authentication/jwt-bearer), | ||
which allows a client application to obtain an access token using a JSON Web Token (JWT) [_assertion_](https://docs.commercelayer.io/core/authentication/jwt-bearer#creating-the-jwt-assertion). | ||
You can use this code to create an _assertion_: | ||
```ts | ||
const assertion = await createAssertion({ | ||
payload: { | ||
'https://commercelayer.io/claims': { | ||
owner: { | ||
type: 'Customer', | ||
id: '4tepftJsT2' | ||
}, | ||
custom_claim: { | ||
customer: { | ||
first_name: 'John', | ||
last_name: 'Doe' | ||
} | ||
} | ||
} | ||
} | ||
}) | ||
``` | ||
You can now get an access token using the `urn:ietf:params:oauth:grant-type:jwt-bearer` grant type: | ||
```ts | ||
import { authenticate } from '@commercelayer/js-auth' | ||
const auth = await authenticate('urn:ietf:params:oauth:grant-type:jwt-bearer', { | ||
clientId: 'your-client-id', | ||
clientSecret: 'your-client-secret', | ||
scope: 'market:code:europe', | ||
assertion | ||
}) | ||
console.log('My access token: ', auth.accessToken) | ||
console.log('Expiration date: ', auth.expires) | ||
``` | ||
### Revoking a token | ||
Any previously generated access tokens (refresh tokens included) can be [revoked](https://docs.commercelayer.io/core/authentication/revoking-a-token) before their natural expiration date. | ||
```ts | ||
import { revoke } from '@commercelayer/js-auth' | ||
await revoke({ | ||
clientId: 'your-client-id', | ||
clientSecret: 'your-client-secret', | ||
token: 'a-generated-access-token' | ||
}) | ||
``` | ||
## Utilities | ||
@@ -211,0 +271,0 @@ |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
74750
345
316
7
4