Socket
Socket
Sign inDemoInstall

oauth4webapi

Package Overview
Dependencies
Maintainers
1
Versions
45
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

oauth4webapi - npm Package Compare versions

Comparing version 1.2.2 to 1.3.0

43

build/index.d.ts

@@ -706,2 +706,27 @@ /** @ignore */

export declare const skipSubjectCheck: unique symbol;
export interface SkipJWTSignatureCheckOptions {
/**
* DANGER ZONE
*
* When JWT assertions are received via direct communication between the Client and the
* Token/UserInfo/Introspection endpoint (which they are in this library's supported profiles and
* exposed functions) the TLS server validation MAY be used to validate the issuer in place of
* checking the assertion's signature.
*
* Set this to `true` to omit verifying the JWT assertion's signature (e.g. ID Token, JWT Signed
* Introspection, or JWT Signed UserInfo Response).
*
* Setting this to `true` also means that:
*
* - The Authorization Server's JSON Web Key Set will not be requested. That is useful for
* javascript runtimes that execute on the edge and cannot reliably share an in-memory cache of
* the JSON Web Key Set in between invocations.
* - Any JWS Algorithm may be used, not just the {@link JWSAlgorithm supported ones}.
*
* Default is `false`.
*/
skipJwtSignatureCheck?: boolean;
}
export interface ProcessUserInfoResponseOptions extends HttpRequestOptions, SkipJWTSignatureCheckOptions {
}
/**

@@ -723,3 +748,3 @@ * Validates Response instance to be one coming from the

*/
export declare function processUserInfoResponse(as: AuthorizationServer, client: Client, expectedSubject: string | typeof skipSubjectCheck, response: Response, options?: HttpRequestOptions): Promise<UserInfoResponse>;
export declare function processUserInfoResponse(as: AuthorizationServer, client: Client, expectedSubject: string | typeof skipSubjectCheck, response: Response, options?: ProcessUserInfoResponseOptions): Promise<UserInfoResponse>;
export interface TokenEndpointRequestOptions extends HttpRequestOptions, AuthenticatedRequestOptions, DPoPRequestOptions {

@@ -760,2 +785,4 @@ /** Any additional parameters to send. This cannot override existing parameter values. */

export declare function getValidatedIdTokenClaims(ref: TokenEndpointResponse): IDToken | undefined;
export interface ProcessRefreshTokenResponseOptions extends HttpRequestOptions, SkipJWTSignatureCheckOptions {
}
/**

@@ -775,3 +802,3 @@ * Validates Refresh Token Grant Response instance to be one coming from the

*/
export declare function processRefreshTokenResponse(as: AuthorizationServer, client: Client, response: Response, options?: HttpRequestOptions): Promise<TokenEndpointResponse | OAuth2Error>;
export declare function processRefreshTokenResponse(as: AuthorizationServer, client: Client, response: Response, options?: ProcessRefreshTokenResponseOptions): Promise<TokenEndpointResponse | OAuth2Error>;
/**

@@ -863,2 +890,4 @@ * Performs an Authorization Code grant request at the

export declare const skipAuthTimeCheck: unique symbol;
export interface ProcessAuthorizationCodeOpenIDResponseOptions extends HttpRequestOptions, SkipJWTSignatureCheckOptions {
}
/**

@@ -884,3 +913,3 @@ * (OpenID Connect only) Validates Authorization Code Grant Response instance to be one coming from

*/
export declare function processAuthorizationCodeOpenIDResponse(as: AuthorizationServer, client: Client, response: Response, expectedNonce?: string | typeof expectNoNonce, maxAge?: number | typeof skipAuthTimeCheck, options?: HttpRequestOptions): Promise<OpenIDTokenEndpointResponse | OAuth2Error>;
export declare function processAuthorizationCodeOpenIDResponse(as: AuthorizationServer, client: Client, response: Response, expectedNonce?: string | typeof expectNoNonce, maxAge?: number | typeof skipAuthTimeCheck, options?: ProcessAuthorizationCodeOpenIDResponseOptions): Promise<OpenIDTokenEndpointResponse | OAuth2Error>;
/**

@@ -1000,2 +1029,4 @@ * (OAuth 2.0 without OpenID Connect only) Validates Authorization Code Grant Response instance to

}
export interface ProcessIntrospectionResponseOptions extends HttpRequestOptions, SkipJWTSignatureCheckOptions {
}
/**

@@ -1015,3 +1046,3 @@ * Validates Response instance to be one coming from the

*/
export declare function processIntrospectionResponse(as: AuthorizationServer, client: Client, response: Response, options?: HttpRequestOptions): Promise<IntrospectionResponse | OAuth2Error>;
export declare function processIntrospectionResponse(as: AuthorizationServer, client: Client, response: Response, options?: ProcessIntrospectionResponseOptions): Promise<IntrospectionResponse | OAuth2Error>;
/** @ignore */

@@ -1151,2 +1182,4 @@ export interface JwksRequestOptions extends HttpRequestOptions {

export declare function deviceCodeGrantRequest(as: AuthorizationServer, client: Client, deviceCode: string, options?: TokenEndpointRequestOptions): Promise<Response>;
export interface ProcessDeviceCodeResponseOptions extends HttpRequestOptions, SkipJWTSignatureCheckOptions {
}
/**

@@ -1165,3 +1198,3 @@ * Validates Device Authorization Grant Response instance to be one coming from the

*/
export declare function processDeviceCodeResponse(as: AuthorizationServer, client: Client, response: Response, options?: HttpRequestOptions): Promise<TokenEndpointResponse | OAuth2Error>;
export declare function processDeviceCodeResponse(as: AuthorizationServer, client: Client, response: Response, options?: ProcessDeviceCodeResponseOptions): Promise<TokenEndpointResponse | OAuth2Error>;
export interface GenerateKeyPairOptions {

@@ -1168,0 +1201,0 @@ /** Indicates whether or not the private key may be exported. Default is `false`. */

92

build/index.js
let USER_AGENT;
if (typeof navigator === 'undefined' || !navigator.userAgent?.startsWith?.('Mozilla/5.0 ')) {
const NAME = 'oauth4webapi';
const VERSION = 'v1.2.2';
const VERSION = 'v1.3.0';
USER_AGENT = `${NAME}/${VERSION}`;

@@ -735,6 +735,5 @@ }

if (getContentType(response) === 'application/jwt') {
if (typeof as.jwks_uri !== 'string') {
throw new TypeError('"as.jwks_uri" must be a string');
}
const { claims } = await validateJwt(await preserveBodyStream(response).text(), checkSigningAlgorithm.bind(undefined, client.userinfo_signed_response_alg, as.userinfo_signing_alg_values_supported), getPublicSigKeyFromIssuerJwksUri.bind(undefined, as, options))
const { claims } = await validateJwt(await preserveBodyStream(response).text(), checkSigningAlgorithm.bind(undefined, client.userinfo_signed_response_alg, as.userinfo_signing_alg_values_supported), options?.skipJwtSignatureCheck !== true
? getPublicSigKeyFromIssuerJwksUri.bind(undefined, as, options)
: noSignatureCheck)
.then(validateOptionalAudience.bind(undefined, client.client_id))

@@ -774,39 +773,2 @@ .then(validateOptionalIssuer.bind(undefined, as.issuer));

}
function padded(buf, length) {
const out = new Uint8Array(length);
out.set(buf);
return out;
}
function timingSafeEqual(a, b) {
const len = Math.max(a.byteLength, b.byteLength);
a = padded(a, len);
b = padded(b, len);
let out = 0;
let i = -1;
while (++i < len) {
out |= a[i] ^ b[i];
}
return out === 0;
}
async function idTokenHash(alg, data) {
let algorithm;
switch (alg) {
case 'RS256':
case 'PS256':
case 'ES256':
algorithm = { name: 'SHA-256' };
break;
case 'EdDSA':
algorithm = { name: 'SHA-512' };
break;
default:
throw new UnsupportedOperationError();
}
const digest = await crypto.subtle.digest(algorithm, buf(data));
return b64u(digest.slice(0, digest.byteLength / 2));
}
async function idTokenHashMatches(alg, data, actual) {
const expected = await idTokenHash(alg, data);
return timingSafeEqual(buf(actual), buf(expected));
}
async function authenticatedRequest(as, client, method, url, body, headers, options) {

@@ -852,3 +814,3 @@ await clientAuthentication(as, client, body, headers, options?.clientPrivateKey);

}
async function processGenericAccessTokenResponse(as, client, response, options, ignoreIdToken = false, ignoreRefreshToken = false) {
async function processGenericAccessTokenResponse(as, client, response, options, ignoreIdToken = false, ignoreRefreshToken = false, skipSignatureCheck = false) {
assertAs(as);

@@ -903,6 +865,5 @@ assertClient(client);

if (json.id_token) {
if (typeof as.jwks_uri !== 'string') {
throw new TypeError('"as.jwks_uri" must be a string');
}
const { header, claims } = await validateJwt(json.id_token, checkSigningAlgorithm.bind(undefined, client.id_token_signed_response_alg, as.id_token_signing_alg_values_supported), getPublicSigKeyFromIssuerJwksUri.bind(undefined, as, options))
const { claims } = await validateJwt(json.id_token, checkSigningAlgorithm.bind(undefined, client.id_token_signed_response_alg, as.id_token_signing_alg_values_supported), skipSignatureCheck !== true
? getPublicSigKeyFromIssuerJwksUri.bind(undefined, as, options)
: noSignatureCheck)
.then(validatePresence.bind(undefined, ['aud', 'exp', 'iat', 'iss', 'sub']))

@@ -917,8 +878,2 @@ .then(validateIssuer.bind(undefined, as.issuer))

}
if (claims.at_hash !== undefined) {
if (typeof claims.at_hash !== 'string' ||
!(await idTokenHashMatches(header.alg, json.access_token, claims.at_hash))) {
throw new OPE('unexpected ID Token "at_hash" (access token hash) claim value');
}
}
idTokenClaims.set(json, claims);

@@ -930,3 +885,3 @@ }

export async function processRefreshTokenResponse(as, client, response, options) {
return processGenericAccessTokenResponse(as, client, response, options);
return processGenericAccessTokenResponse(as, client, response, options, undefined, undefined, options?.skipJwtSignatureCheck === true);
}

@@ -1002,3 +957,3 @@ function validateOptionalAudience(expected, result) {

export async function processAuthorizationCodeOpenIDResponse(as, client, response, expectedNonce, maxAge, options) {
const result = await processGenericAccessTokenResponse(as, client, response, options);
const result = await processGenericAccessTokenResponse(as, client, response, options, undefined, undefined, options?.skipJwtSignatureCheck === true);
if (isOAuth2Error(result)) {

@@ -1147,6 +1102,5 @@ return result;

if (getContentType(response) === 'application/token-introspection+jwt') {
if (typeof as.jwks_uri !== 'string') {
throw new TypeError('"as.jwks_uri" must be a string');
}
const { claims } = await validateJwt(await preserveBodyStream(response).text(), checkSigningAlgorithm.bind(undefined, client.introspection_signed_response_alg, as.introspection_signing_alg_values_supported), getPublicSigKeyFromIssuerJwksUri.bind(undefined, as, options))
const { claims } = await validateJwt(await preserveBodyStream(response).text(), checkSigningAlgorithm.bind(undefined, client.introspection_signed_response_alg, as.introspection_signing_alg_values_supported), options?.skipJwtSignatureCheck !== true
? getPublicSigKeyFromIssuerJwksUri.bind(undefined, as, options)
: noSignatureCheck)
.then(checkJwtType.bind(undefined, 'token-introspection+jwt'))

@@ -1271,4 +1225,5 @@ .then(validatePresence.bind(undefined, ['aud', 'iat', 'iss']))

}
const noSignatureCheck = Symbol();
async function validateJwt(jws, checkAlg, getKey) {
const { 0: protectedHeader, 1: payload, 2: signature, length } = jws.split('.');
const { 0: protectedHeader, 1: payload, 2: encodedSignature, length } = jws.split('.');
if (length === 5) {

@@ -1294,7 +1249,10 @@ throw new UnsupportedOperationError('JWE structure JWTs are not supported');

}
const key = await getKey(header);
const input = `${protectedHeader}.${payload}`;
const verified = await crypto.subtle.verify(subtleAlgorithm(key), key, b64u(signature), buf(input));
if (!verified) {
throw new OPE('JWT signature verification failed');
const signature = b64u(encodedSignature);
if (getKey !== noSignatureCheck) {
const key = await getKey(header);
const input = `${protectedHeader}.${payload}`;
const verified = await crypto.subtle.verify(subtleAlgorithm(key), key, signature, buf(input));
if (!verified) {
throw new OPE('JWT signature verification failed');
}
}

@@ -1344,3 +1302,3 @@ let claims;

}
return { header, claims };
return { header, claims, signature };
}

@@ -1550,3 +1508,3 @@ export async function validateJwtAuthResponse(as, client, parameters, expectedState, options) {

export async function processDeviceCodeResponse(as, client, response, options) {
return processGenericAccessTokenResponse(as, client, response, options);
return processGenericAccessTokenResponse(as, client, response, options, undefined, undefined, options?.skipJwtSignatureCheck === true);
}

@@ -1553,0 +1511,0 @@ export async function generateKeyPair(alg, options) {

{
"name": "oauth4webapi",
"version": "1.2.2",
"version": "1.3.0",
"description": "OAuth 2 / OpenID Connect for Web Platform API JavaScript runtimes",

@@ -13,7 +13,10 @@ "keywords": [

"client",
"cloudflare-workers",
"cloudflare",
"deno",
"edge",
"electron",
"fapi",
"javascript",
"netlify",
"next",
"nextjs",

@@ -27,3 +30,4 @@ "node",

"openid",
"vercel-edge"
"vercel",
"workers"
],

@@ -62,20 +66,20 @@ "homepage": "https://github.com/panva/oauth4webapi",

"@esbuild-kit/esm-loader": "^2.5.0",
"@types/node": "^18.11.2",
"@types/node": "^18.11.7",
"@types/qunit": "^2.19.3",
"ava": "^4.3.3",
"edge-runtime": "^1.1.0-beta.40",
"jose": "^4.10.0",
"patch-package": "^6.4.7",
"ava": "^5.0.1",
"edge-runtime": "^2.0.0",
"jose": "^4.10.4",
"patch-package": "^6.5.0",
"prettier": "^2.7.1",
"prettier-plugin-jsdoc": "^0.4.2",
"qunit": "^2.19.2",
"qunit": "^2.19.3",
"testcafe": "^2.0.1",
"testcafe-browser-provider-browserstack": "^1.14.0",
"timekeeper": "^2.2.0",
"typedoc": "^0.23.17",
"typedoc": "^0.23.19",
"typedoc-plugin-markdown": "^3.13.6",
"typescript": "^4.8.4",
"undici": "^5.11.0",
"undici": "^5.12.0",
"workerd": "^1.20220926.3"
}
}

@@ -55,22 +55,14 @@ # OAuth 2 / OpenID Connect for Web Platform API JavaScript runtimes

## Runtime requirements
## Supported Runtimes
The supported JavaScript runtimes include ones that
The supported JavaScript runtimes include ones that support the utilized Web API globals and standard built-in objects
- are reasonably up to date ECMAScript (targets ES2020, but may be further transpiled for compatibility)
- support required Web API globals and standard built-in objects
- [Fetch API][] and its related globals [fetch][], [Response][], [Headers][]
- [Web Crypto API][] and its related globals [crypto][], [CryptoKey][]
- [Encoding API][] and its related globals [TextEncoder][], [TextDecoder][]
- [URL API][] and its related globals [URL][], [URLSearchParams][]
- [atob][] and [btoa][]
- [Uint8Array][]
- These are (not an exhaustive list):
- Browsers
- Cloudflare Workers
- Deno
- Electron
- Next.js Middlewares
- Node.js ([runtime flags may be needed](https://github.com/panva/oauth4webapi/issues/8))
- Vercel Edge Functions
These are _(this is not an exhaustive list)_:
- Browsers
- Cloudflare Workers
- Deno
- Electron
- Netlify Edge
- Node.js ([runtime flags may be needed](https://github.com/panva/oauth4webapi/issues/8))
- Vercel's Edge Runtime

@@ -85,18 +77,1 @@ ## Out of scope

- Automatic polyfills of any kind
[web crypto api]: https://developer.mozilla.org/en-US/docs/Web/API/Web_Crypto_API
[fetch api]: https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API
[fetch]: https://developer.mozilla.org/en-US/docs/Web/API/fetch
[textdecoder]: https://developer.mozilla.org/en-US/docs/Web/API/TextDecoder
[textencoder]: https://developer.mozilla.org/en-US/docs/Web/API/TextEncoder
[btoa]: https://developer.mozilla.org/en-US/docs/Web/API/btoa
[atob]: https://developer.mozilla.org/en-US/docs/Web/API/atob
[uint8array]: https://developer.mozilla.org/en-US/docs/Web/API/Uint8Array
[response]: https://developer.mozilla.org/en-US/docs/Web/API/Response
[headers]: https://developer.mozilla.org/en-US/docs/Web/API/Headers
[crypto]: https://developer.mozilla.org/en-US/docs/Web/API/crypto
[cryptokey]: https://developer.mozilla.org/en-US/docs/Web/API/CryptoKey
[urlsearchparams]: https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParams
[encoding api]: https://developer.mozilla.org/en-US/docs/Web/API/Encoding_API
[url api]: https://developer.mozilla.org/en-US/docs/Web/API/URL_API
[url]: https://developer.mozilla.org/en-US/docs/Web/API/URL
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc