New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

fetch-mw-oauth2

Package Overview
Dependencies
Maintainers
1
Versions
36
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

fetch-mw-oauth2 - npm Package Compare versions

Comparing version 2.0.7 to 2.0.8

2

browser/fetch-mw-oauth2.min.js

@@ -1,2 +0,2 @@

!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.fetchMwOAuth2=t():e.fetchMwOAuth2=t()}(self,(()=>(()=>{"use strict";var e={934:(e,t,r)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.generateQueryString=t.tokenResponseToOAuth2Token=t.OAuth2Client=void 0;const n=r(443),i=r(618);function o(e,t){return new URL(e,t).toString()}function s(e){return e.then((e=>{var t;return{accessToken:e.access_token,expiresAt:e.expires_in?Date.now()+1e3*e.expires_in:null,refreshToken:null!==(t=e.refresh_token)&&void 0!==t?t:null}}))}function a(e){return new URLSearchParams(Object.fromEntries(Object.entries(e).filter((([e,t])=>void 0!==t)))).toString()}t.OAuth2Client=class{constructor(e){this.discoveryDone=!1,this.serverMetadata=null,this.settings=e}async refreshToken(e){if(!e.refreshToken)throw new Error("This token didn't have a refreshToken. It's not possible to refresh this");const t={grant_type:"refresh_token",refresh_token:e.refreshToken};return this.settings.clientSecret||(t.client_id=this.settings.clientId),s(this.request("tokenEndpoint",t))}async clientCredentials(e){var t;const r={grant_type:"client_credentials",scope:null===(t=null==e?void 0:e.scope)||void 0===t?void 0:t.join(" ")};if(!this.settings.clientSecret)throw new Error("A clientSecret must be provied to use client_credentials");return s(this.request("tokenEndpoint",r))}async password(e){var t;const r={grant_type:"password",...e,scope:null===(t=e.scope)||void 0===t?void 0:t.join(" ")};if(!this.settings.clientSecret)throw new Error("A clientSecret must be provied to use client_credentials");return s(this.request("tokenEndpoint",r))}authorizationCode(e){return new i.OAuth2AuthorizationCodeClient(this,e.redirectUri,e.state)}async introspect(e){const t={token:e.accessToken,token_type_hint:"access_token"};return this.request("introspectionEndpoint",t)}async getEndpoint(e){if(void 0!==this.settings[e])return o(this.settings[e],this.settings.server);if("discoveryEndpoint"!==e&&(await this.discover(),void 0!==this.settings[e]))return o(this.settings[e],this.settings.server);if(!this.settings.server)throw new Error(`Could not determine the location of ${e}. Either specify ${e} in the settings, or the "server" endpoint to let the client discover it.`);switch(e){case"authorizationEndpoint":return o("/authorize",this.settings.server);case"tokenEndpoint":return o("/token",this.settings.server);case"discoveryEndpoint":return o("/.well-known/oauth-authorization-server",this.settings.server);case"introspectionEndpoint":return o("/introspect",this.settings.server)}}async discover(){if(this.discoveryDone)return;let e;this.discoveryDone=!0;try{e=await this.getEndpoint("discoveryEndpoint")}catch(e){return void console.warn('[oauth2] OAuth2 discovery endpoint could not be determined. Either specify the "server" or "discoveryEndpoint')}const t=await fetch(e,{headers:{Accept:"application/json"}});if(!t.ok)return;if(!t.headers.has("Content-Type")||t.headers.get("Content-Type").startsWith("application/json"))return void console.warn("[oauth2] OAuth2 discovery endpoint was not a JSON response. Response is ignored");this.serverMetadata=await t.json();const r=[["authorization_endpoint","authorizationEndpoint"],["token_endpoint","tokenEndpoint"],["introspection_endpoint","introspectionEndpoint"]];if(null!==this.serverMetadata)for(const[t,n]of r)this.serverMetadata[t]&&(this.settings[n]=o(this.serverMetadata[t],e))}async request(e,t){const r=await this.getEndpoint(e),i={};if("authorization_code"!==t.grant_type&&this.settings.clientSecret){const e=btoa(this.settings.clientId+":"+this.settings.clientSecret);i.Authorization="Basic "+e}const o=await fetch(r,{method:"POST",body:a(t),headers:i});if(o.ok)return await o.json();let s,h,c;throw o.headers.has("Content-Type")&&o.headers.get("Content-Type").startsWith("application/json")&&(s=await o.json()),(null==s?void 0:s.error)?(h="OAuth2 error "+s.error+".",s.error_description&&(h+=" "+s.error_description),c=s.error):(h="HTTP Error "+o.status+" "+o.statusText,401===o.status&&this.settings.clientSecret&&(h+=". It's likely that the clientId and/or clientSecret was incorrect"),c=null),new n.OAuth2Error(h,c,o.status)}},t.tokenResponseToOAuth2Token=s,t.generateQueryString=a},618:(e,t,r)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.generateCodeVerifier=t.OAuth2AuthorizationCodeClient=void 0;const n=r(934),i=r(443);async function o(e){return["S256",a(await crypto.subtle.digest("SHA-256",s(e)))]}function s(e){const t=new Uint8Array(e.length);for(let r=0;r<e.length;r++)t[r]=255&e.charCodeAt(r);return t}function a(e){return btoa(String.fromCharCode(...new Uint8Array(e))).replace(/\+/g,"-").replace(/\//g,"_").replace(/=+$/,"")}t.OAuth2AuthorizationCodeClient=class{constructor(e,t,r,n){this.client=e,this.redirectUri=t,this.state=r,this.codeVerifier=n}async getAuthorizeUri(){const[e,t]=await Promise.all([this.codeVerifier?o(this.codeVerifier):void 0,this.client.getEndpoint("authorizationEndpoint")]),r={response_type:"code",client_id:this.client.settings.clientId,redirect_uri:this.redirectUri,code_challenge_method:null==e?void 0:e[0],code_challenge:null==e?void 0:e[1]};return this.state&&(r.state=this.state),t+"?"+(0,n.generateQueryString)(r)}async validateResponse(e){var t;const r=new URL(e).searchParams;if(r.has("error"))throw new i.OAuth2Error(null!==(t=r.get("error_description"))&&void 0!==t?t:"OAuth2 error",r.get("error"),0);if(!r.has("code"))throw new Error(`The url did not contain a code parameter ${e}`);if(!r.has("state"))throw new Error(`The url did not contain state parameter ${e}`);if(this.state!==r.get("state"))throw new Error(`The "state" parameter in the url did not match the expected value of ${this.state}`);return{code:r.get("code")}}async getToken(e){const t={grant_type:"authorization_code",code:e.code,redirect_uri:this.redirectUri,client_id:this.client.settings.clientId,code_verifier:this.codeVerifier};return(0,n.tokenResponseToOAuth2Token)(this.client.request("tokenEndpoint",t))}},t.generateCodeVerifier=function(){const e=new Uint8Array(32);return crypto.getRandomValues(e),a(e)}},443:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.OAuth2Error=void 0;class r extends Error{constructor(e,t,r){super(e),this.oauth2Code=t,this.httpCode=r}}t.OAuth2Error=r},13:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.OAuth2Fetch=void 0,t.OAuth2Fetch=class{constructor(e){this.token=null,this.activeRefresh=null,this.refreshTimer=null,this.options=e,e.getStoredToken&&(async()=>{this.token=await e.getStoredToken()})(),this.scheduleRefresh()}async fetch(e,t){const r=new Request(e,t);return this.mw()(r,(e=>fetch(e)))}mw(){return async(e,t)=>{const r=await this.getAccessToken();let n=e.clone();n.headers.set("Authorization","Bearer "+r);let i=await t(n);if(!i.ok&&401===i.status){const r=await this.refreshToken();n=e.clone(),n.headers.set("Authorization","Bearer "+r.accessToken),i=await t(n)}return i}}async getToken(){return this.token&&(null===this.token.expiresAt||this.token.expiresAt>Date.now())?this.token:this.refreshToken()}async getAccessToken(){return(await this.getToken()).accessToken}async refreshToken(){var e,t;if(this.activeRefresh)return this.activeRefresh;const r=this.token;this.activeRefresh=(async()=>{var e,t;let n=null;try{(null==r?void 0:r.refreshToken)&&(n=await this.options.client.refreshToken(r))}catch(e){console.warn("[oauth2] refresh token not accepted, we'll try reauthenticating")}if(n||(n=await this.options.getNewToken()),!n){const r=new Error("Unableto obtain OAuth2 tokens, a full reauth may be needed");throw null===(t=(e=this.options).onError)||void 0===t||t.call(e,r),r}return n})();try{const r=await this.activeRefresh;return this.token=r,null===(t=(e=this.options).storeToken)||void 0===t||t.call(e,r),this.scheduleRefresh(),r}catch(e){throw this.options.onError&&this.options.onError(e),e}finally{this.activeRefresh=null}}scheduleRefresh(){if(this.refreshTimer&&(clearTimeout(this.refreshTimer),this.refreshTimer=null),!this.token||!this.token.expiresAt||!this.token.refreshToken)return;const e=this.token.expiresAt-Date.now();e<12e4||(this.refreshTimer=setTimeout((async()=>{try{await this.refreshToken()}catch(e){console.error("[fetch-mw-oauth2] error while doing a background OAuth2 auto-refresh",e)}}),e-6e4))}}}},t={};function r(n){var i=t[n];if(void 0!==i)return i.exports;var o=t[n]={exports:{}};return e[n](o,o.exports,r),o.exports}var n={};return(()=>{var e=n;Object.defineProperty(e,"__esModule",{value:!0}),e.OAuth2Error=e.OAuth2Fetch=e.generateCodeVerifier=e.OAuth2AuthorizationCodeClient=e.OAuth2Client=void 0;var t=r(934);Object.defineProperty(e,"OAuth2Client",{enumerable:!0,get:function(){return t.OAuth2Client}});var i=r(618);Object.defineProperty(e,"OAuth2AuthorizationCodeClient",{enumerable:!0,get:function(){return i.OAuth2AuthorizationCodeClient}}),Object.defineProperty(e,"generateCodeVerifier",{enumerable:!0,get:function(){return i.generateCodeVerifier}});var o=r(13);Object.defineProperty(e,"OAuth2Fetch",{enumerable:!0,get:function(){return o.OAuth2Fetch}});var s=r(443);Object.defineProperty(e,"OAuth2Error",{enumerable:!0,get:function(){return s.OAuth2Error}})})(),n})()));
!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.fetchMwOAuth2=t():e.fetchMwOAuth2=t()}(self,(()=>(()=>{"use strict";var e={934:(e,t,r)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.generateQueryString=t.tokenResponseToOAuth2Token=t.OAuth2Client=void 0;const n=r(443),i=r(618);function o(e,t){return new URL(e,t).toString()}function s(e){return e.then((e=>{var t;return{accessToken:e.access_token,expiresAt:e.expires_in?Date.now()+1e3*e.expires_in:null,refreshToken:null!==(t=e.refresh_token)&&void 0!==t?t:null}}))}function a(e){return new URLSearchParams(Object.fromEntries(Object.entries(e).filter((([e,t])=>void 0!==t)))).toString()}t.OAuth2Client=class{constructor(e){this.discoveryDone=!1,this.serverMetadata=null,this.settings=e}async refreshToken(e){if(!e.refreshToken)throw new Error("This token didn't have a refreshToken. It's not possible to refresh this");const t={grant_type:"refresh_token",refresh_token:e.refreshToken};return this.settings.clientSecret||(t.client_id=this.settings.clientId),s(this.request("tokenEndpoint",t))}async clientCredentials(e){var t;const r={grant_type:"client_credentials",scope:null===(t=null==e?void 0:e.scope)||void 0===t?void 0:t.join(" ")};if(!this.settings.clientSecret)throw new Error("A clientSecret must be provied to use client_credentials");return s(this.request("tokenEndpoint",r))}async password(e){var t;const r={grant_type:"password",...e,scope:null===(t=e.scope)||void 0===t?void 0:t.join(" ")};if(!this.settings.clientSecret)throw new Error("A clientSecret must be provied to use client_credentials");return s(this.request("tokenEndpoint",r))}get authorizationCode(){return new i.OAuth2AuthorizationCodeClient(this)}async introspect(e){const t={token:e.accessToken,token_type_hint:"access_token"};return this.request("introspectionEndpoint",t)}async getEndpoint(e){if(void 0!==this.settings[e])return o(this.settings[e],this.settings.server);if("discoveryEndpoint"!==e&&(await this.discover(),void 0!==this.settings[e]))return o(this.settings[e],this.settings.server);if(!this.settings.server)throw new Error(`Could not determine the location of ${e}. Either specify ${e} in the settings, or the "server" endpoint to let the client discover it.`);switch(e){case"authorizationEndpoint":return o("/authorize",this.settings.server);case"tokenEndpoint":return o("/token",this.settings.server);case"discoveryEndpoint":return o("/.well-known/oauth-authorization-server",this.settings.server);case"introspectionEndpoint":return o("/introspect",this.settings.server)}}async discover(){if(this.discoveryDone)return;let e;this.discoveryDone=!0;try{e=await this.getEndpoint("discoveryEndpoint")}catch(e){return void console.warn('[oauth2] OAuth2 discovery endpoint could not be determined. Either specify the "server" or "discoveryEndpoint')}const t=await fetch(e,{headers:{Accept:"application/json"}});if(!t.ok)return;if(!t.headers.has("Content-Type")||t.headers.get("Content-Type").startsWith("application/json"))return void console.warn("[oauth2] OAuth2 discovery endpoint was not a JSON response. Response is ignored");this.serverMetadata=await t.json();const r=[["authorization_endpoint","authorizationEndpoint"],["token_endpoint","tokenEndpoint"],["introspection_endpoint","introspectionEndpoint"]];if(null!==this.serverMetadata)for(const[t,n]of r)this.serverMetadata[t]&&(this.settings[n]=o(this.serverMetadata[t],e))}async request(e,t){const r=await this.getEndpoint(e),i={};if("authorization_code"!==t.grant_type&&this.settings.clientSecret){const e=btoa(this.settings.clientId+":"+this.settings.clientSecret);i.Authorization="Basic "+e}const o=await fetch(r,{method:"POST",body:a(t),headers:i});if(o.ok)return await o.json();let s,c,h;throw o.headers.has("Content-Type")&&o.headers.get("Content-Type").startsWith("application/json")&&(s=await o.json()),(null==s?void 0:s.error)?(c="OAuth2 error "+s.error+".",s.error_description&&(c+=" "+s.error_description),h=s.error):(c="HTTP Error "+o.status+" "+o.statusText,401===o.status&&this.settings.clientSecret&&(c+=". It's likely that the clientId and/or clientSecret was incorrect"),h=null),new n.OAuth2Error(c,h,o.status)}},t.tokenResponseToOAuth2Token=s,t.generateQueryString=a},618:(e,t,r)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.generateCodeVerifier=t.OAuth2AuthorizationCodeClient=void 0;const n=r(934),i=r(443);async function o(e){return["S256",a(await crypto.subtle.digest("SHA-256",s(e)))]}function s(e){const t=new Uint8Array(e.length);for(let r=0;r<e.length;r++)t[r]=255&e.charCodeAt(r);return t}function a(e){return btoa(String.fromCharCode(...new Uint8Array(e))).replace(/\+/g,"-").replace(/\//g,"_").replace(/=+$/,"")}t.OAuth2AuthorizationCodeClient=class{constructor(e){this.client=e}async getAuthorizeUri(e){const[t,r]=await Promise.all([e.codeVerifier?o(e.codeVerifier):void 0,this.client.getEndpoint("authorizationEndpoint")]),i={response_type:"code",client_id:this.client.settings.clientId,redirect_uri:e.redirectUri,code_challenge_method:null==t?void 0:t[0],code_challenge:null==t?void 0:t[1]};return e.state&&(i.state=e.state),r+"?"+(0,n.generateQueryString)(i)}async getTokenFromCodeRedirect(e,t){const{code:r}=await this.validateResponse(e,{state:t.state});return this.getToken({code:r,redirectUri:t.redirectUri,codeVerifier:t.codeVerifier})}async validateResponse(e,t){var r;const n=new URL(e).searchParams;if(n.has("error"))throw new i.OAuth2Error(null!==(r=n.get("error_description"))&&void 0!==r?r:"OAuth2 error",n.get("error"),0);if(!n.has("code"))throw new Error(`The url did not contain a code parameter ${e}`);if(!n.has("state"))throw new Error(`The url did not contain state parameter ${e}`);if(t.state&&t.state!==n.get("state"))throw new Error(`The "state" parameter in the url did not match the expected value of ${t.state}`);return{code:n.get("code")}}async getToken(e){const t={grant_type:"authorization_code",code:e.code,redirect_uri:e.redirectUri,client_id:this.client.settings.clientId,code_verifier:e.codeVerifier};return(0,n.tokenResponseToOAuth2Token)(this.client.request("tokenEndpoint",t))}},t.generateCodeVerifier=function(){const e=new Uint8Array(32);return crypto.getRandomValues(e),a(e)}},443:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.OAuth2Error=void 0;class r extends Error{constructor(e,t,r){super(e),this.oauth2Code=t,this.httpCode=r}}t.OAuth2Error=r},13:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.OAuth2Fetch=void 0,t.OAuth2Fetch=class{constructor(e){this.token=null,this.activeRefresh=null,this.refreshTimer=null,this.options=e,e.getStoredToken&&(async()=>{this.token=await e.getStoredToken()})(),this.scheduleRefresh()}async fetch(e,t){const r=new Request(e,t);return this.mw()(r,(e=>fetch(e)))}mw(){return async(e,t)=>{const r=await this.getAccessToken();let n=e.clone();n.headers.set("Authorization","Bearer "+r);let i=await t(n);if(!i.ok&&401===i.status){const r=await this.refreshToken();n=e.clone(),n.headers.set("Authorization","Bearer "+r.accessToken),i=await t(n)}return i}}async getToken(){return this.token&&(null===this.token.expiresAt||this.token.expiresAt>Date.now())?this.token:this.refreshToken()}async getAccessToken(){return(await this.getToken()).accessToken}async refreshToken(){var e,t;if(this.activeRefresh)return this.activeRefresh;const r=this.token;this.activeRefresh=(async()=>{var e,t;let n=null;try{(null==r?void 0:r.refreshToken)&&(n=await this.options.client.refreshToken(r))}catch(e){console.warn("[oauth2] refresh token not accepted, we'll try reauthenticating")}if(n||(n=await this.options.getNewToken()),!n){const r=new Error("Unableto obtain OAuth2 tokens, a full reauth may be needed");throw null===(t=(e=this.options).onError)||void 0===t||t.call(e,r),r}return n})();try{const r=await this.activeRefresh;return this.token=r,null===(t=(e=this.options).storeToken)||void 0===t||t.call(e,r),this.scheduleRefresh(),r}catch(e){throw this.options.onError&&this.options.onError(e),e}finally{this.activeRefresh=null}}scheduleRefresh(){if(this.refreshTimer&&(clearTimeout(this.refreshTimer),this.refreshTimer=null),!this.token||!this.token.expiresAt||!this.token.refreshToken)return;const e=this.token.expiresAt-Date.now();e<12e4||(this.refreshTimer=setTimeout((async()=>{try{await this.refreshToken()}catch(e){console.error("[fetch-mw-oauth2] error while doing a background OAuth2 auto-refresh",e)}}),e-6e4))}}}},t={};function r(n){var i=t[n];if(void 0!==i)return i.exports;var o=t[n]={exports:{}};return e[n](o,o.exports,r),o.exports}var n={};return(()=>{var e=n;Object.defineProperty(e,"__esModule",{value:!0}),e.OAuth2Error=e.OAuth2Fetch=e.generateCodeVerifier=e.OAuth2AuthorizationCodeClient=e.OAuth2Client=void 0;var t=r(934);Object.defineProperty(e,"OAuth2Client",{enumerable:!0,get:function(){return t.OAuth2Client}});var i=r(618);Object.defineProperty(e,"OAuth2AuthorizationCodeClient",{enumerable:!0,get:function(){return i.OAuth2AuthorizationCodeClient}}),Object.defineProperty(e,"generateCodeVerifier",{enumerable:!0,get:function(){return i.generateCodeVerifier}});var o=r(13);Object.defineProperty(e,"OAuth2Fetch",{enumerable:!0,get:function(){return o.OAuth2Fetch}});var s=r(443);Object.defineProperty(e,"OAuth2Error",{enumerable:!0,get:function(){return s.OAuth2Error}})})(),n})()));
//# sourceMappingURL=fetch-mw-oauth2.min.js.map

@@ -78,7 +78,8 @@ import { OAuth2Token } from './token';

}): Promise<OAuth2Token>;
authorizationCode(params: {
redirectUri: string;
state: string;
}): OAuth2AuthorizationCodeClient;
/**
* Returns the helper object for the `authorization_code` grant.
*
*/
get authorizationCode(): OAuth2AuthorizationCodeClient;
/**
* Introspect a token

@@ -85,0 +86,0 @@ *

@@ -58,4 +58,8 @@ "use strict";

}
authorizationCode(params) {
return new authorization_code_1.OAuth2AuthorizationCodeClient(this, params.redirectUri, params.state);
/**
* Returns the helper object for the `authorization_code` grant.
*
*/
get authorizationCode() {
return new authorization_code_1.OAuth2AuthorizationCodeClient(this);
}

@@ -62,0 +66,0 @@ /**

@@ -5,6 +5,3 @@ import { OAuth2Client } from '../client';

client: OAuth2Client;
redirectUri: string;
state: string | undefined;
codeVerifier: string | undefined;
constructor(client: OAuth2Client, redirectUri: string, state?: string, codeVerifier?: string);
constructor(client: OAuth2Client);
/**

@@ -14,3 +11,12 @@ * Returns the URi that the user should open in a browser to initiate the

*/
getAuthorizeUri(): Promise<string>;
getAuthorizeUri(params: {
redirectUri: string;
state?: string;
codeVerifier?: string;
}): Promise<string>;
getTokenFromCodeRedirect(url: string | URL, params: {
redirectUri: string;
state?: string;
codeVerifier?: string;
}): Promise<OAuth2Token>;
/**

@@ -23,5 +29,6 @@ * After the user redirected back from the authorization endpoint, the

*/
validateResponse(url: string | URL): Promise<{
validateResponse(url: string | URL, params: {
state?: string;
}): Promise<{
code: string;
codeVerifier?: string;
}>;

@@ -33,4 +40,6 @@ /**

code: string;
redirectUri: string;
codeVerifier?: string;
}): Promise<OAuth2Token>;
}
export declare function generateCodeVerifier(): string;

@@ -7,7 +7,4 @@ "use strict";

class OAuth2AuthorizationCodeClient {
constructor(client, redirectUri, state, codeVerifier) {
constructor(client) {
this.client = client;
this.redirectUri = redirectUri;
this.state = state;
this.codeVerifier = codeVerifier;
}

@@ -18,5 +15,5 @@ /**

*/
async getAuthorizeUri() {
async getAuthorizeUri(params) {
const [codeChallenge, authorizationEndpoint] = await Promise.all([
this.codeVerifier ? getCodeChallenge(this.codeVerifier) : undefined,
params.codeVerifier ? getCodeChallenge(params.codeVerifier) : undefined,
this.client.getEndpoint('authorizationEndpoint')

@@ -27,11 +24,21 @@ ]);

client_id: this.client.settings.clientId,
redirect_uri: this.redirectUri,
redirect_uri: params.redirectUri,
code_challenge_method: codeChallenge === null || codeChallenge === void 0 ? void 0 : codeChallenge[0],
code_challenge: codeChallenge === null || codeChallenge === void 0 ? void 0 : codeChallenge[1],
};
if (this.state) {
query.state = this.state;
if (params.state) {
query.state = params.state;
}
return authorizationEndpoint + '?' + (0, client_1.generateQueryString)(query);
}
async getTokenFromCodeRedirect(url, params) {
const { code } = await this.validateResponse(url, {
state: params.state
});
return this.getToken({
code,
redirectUri: params.redirectUri,
codeVerifier: params.codeVerifier,
});
}
/**

@@ -44,3 +51,3 @@ * After the user redirected back from the authorization endpoint, the

*/
async validateResponse(url) {
async validateResponse(url, params) {
var _a;

@@ -55,4 +62,4 @@ const queryParams = new URL(url).searchParams;

throw new Error(`The url did not contain state parameter ${url}`);
if (this.state !== queryParams.get('state')) {
throw new Error(`The "state" parameter in the url did not match the expected value of ${this.state}`);
if (params.state && params.state !== queryParams.get('state')) {
throw new Error(`The "state" parameter in the url did not match the expected value of ${params.state}`);
}

@@ -70,5 +77,5 @@ return {

code: params.code,
redirect_uri: this.redirectUri,
redirect_uri: params.redirectUri,
client_id: this.client.settings.clientId,
code_verifier: this.codeVerifier,
code_verifier: params.codeVerifier,
};

@@ -75,0 +82,0 @@ return (0, client_1.tokenResponseToOAuth2Token)(this.client.request('tokenEndpoint', body));

{
"name": "fetch-mw-oauth2",
"version": "2.0.7",
"version": "2.0.8",
"description": "Fetch middleware to add OAuth2 support",

@@ -5,0 +5,0 @@ "main": "dist/index.js",

@@ -122,7 +122,7 @@ # fetch-mw-oauth2

This library provides support for all 3 steps, but there's no requirement
This library provides support for these steps, but there's no requirement
to use its functionality as the system is mostly stateless.
```typescript
import { OAuth2Client } from 'client';
import { OAuth2Client, generateCodeVerifier } from 'client';

@@ -137,12 +137,2 @@ const client = new OAuth2Client({

});
const authorizationCode = client.authorizationCode({
// URL in the app that the user should get redirected to after authenticating
redirectUri: 'https://my-app.example/',
// Optional string that can be sent along to the auth server. This value will
// be sent along with the redirect back to the app verbatim.
state: 'some-string',
});
```

@@ -153,50 +143,17 @@

```typescript
// In a browser this might work as follows:
document.location = await authorizationCode.getAuthorizeUri();
```
**Handling the redirect back to the app and obtain token**
```typescript
const codeResponse = await authorizationCode.validateResponse(
document.location
);
const oauth2Token = await authorizationCode.getToken(codeResponse);
```
### PKCE support
Modern OAuth2 server should support PKCE, which improves security.
This library supports PKCE. Luckily you don't need to know in advance whether
your authorization server supports it. If they do, you get the additional
benefit. If not, nothing should break.
To use PKCE, you need to make one extra step when calling `authorizationCode`:
```typescript
import { OAuth2Client, getCodeVerifier } from 'client';
const client = new OAuth2Client({
server: 'https://authserver.example/',
clientId: '...',
// Note, if urls cannot be auto-detected, also specify these:
tokenEndpoint: '/token',
authorizationEndpoint: '/authorize',
});
/**
* IMPORTANT! This returns a random value every time it's called
* This generates a security code that must be passed to the various steps.
* This is used for 'PKCE' which is an advanced security feature.
*
* Because the authorization_code is a multi-step process that likely results
* in the user leaving your website and coming back later, you must store the
* result of this somewhere.
* It doesn't break servers that don't support it, but it makes servers that
* so support it more secure.
*
* The codeVerifier gets used in the first step 'getAuthorizeUrl()` and the
* last step 'getToken()`.
* It's optional to pass this, but recommended.
*/
const codeVerifier = getCodeVerifier();
const authorizationCode = client.authorizationCode({
const codeVerifier = generateCodeVerifier():
// In a browser this might work as follows:
document.location = await authorizationCode.authorizationCode.getAuthorizeUri({
// URL in the app that the user should get redirected to after authenticating

@@ -209,7 +166,36 @@ redirectUri: 'https://my-app.example/',

// Pass the code verifier
codeVerifier,
});
```
**Handling the redirect back to the app and obtain token**
```typescript
const oauth2Token = await client.authorizationCode.getTokenFromCodeRedirect(
document.location,
{
/**
* The redirect URI is not actually used for any redirects, but MUST be the
* same as what you passed earlier to "authorizationCode"
*/
redirectUri: 'https://my-app.example/',
/**
* This is optional, but if it's passed then it also MUST be the same as
* what you passed in the first step.
*
* If set, it will verify that the server sent the exact same state back.
*/
state: 'some-string',
codeVerifier,
}
);
const oauth2Token = await authorizationCode.getToken(codeResponse);
```
### Fetch Wrapper

@@ -249,3 +235,3 @@

// Example
return client.clientCredentials();
return client.clientCredentials();

@@ -252,0 +238,0 @@ // Another example

@@ -145,8 +145,10 @@ import { OAuth2Token } from './token';

authorizationCode(params: {redirectUri: string; state: string}): OAuth2AuthorizationCodeClient {
/**
* Returns the helper object for the `authorization_code` grant.
*
*/
get authorizationCode(): OAuth2AuthorizationCodeClient {
return new OAuth2AuthorizationCodeClient(
this,
params.redirectUri,
params.state,
);

@@ -153,0 +155,0 @@

@@ -9,12 +9,6 @@ import { OAuth2Client, tokenResponseToOAuth2Token, generateQueryString } from '../client';

client: OAuth2Client;
redirectUri: string;
state: string|undefined;
codeVerifier: string|undefined;
constructor(client: OAuth2Client, redirectUri: string, state?: string, codeVerifier?: string) {
constructor(client: OAuth2Client) {
this.client = client;
this.redirectUri = redirectUri;
this.state = state;
this.codeVerifier = codeVerifier;

@@ -27,3 +21,3 @@ }

*/
async getAuthorizeUri(): Promise<string> {
async getAuthorizeUri(params: {redirectUri: string; state?: string; codeVerifier?: string}): Promise<string> {

@@ -34,3 +28,3 @@ const [

] = await Promise.all([
this.codeVerifier ? getCodeChallenge(this.codeVerifier) : undefined,
params.codeVerifier ? getCodeChallenge(params.codeVerifier) : undefined,
this.client.getEndpoint('authorizationEndpoint')

@@ -42,8 +36,8 @@ ]);

client_id: this.client.settings.clientId,
redirect_uri: this.redirectUri,
redirect_uri: params.redirectUri,
code_challenge_method: codeChallenge?.[0],
code_challenge: codeChallenge?.[1],
};
if (this.state) {
query.state = this.state;
if (params.state) {
query.state = params.state;
}

@@ -55,2 +49,16 @@

async getTokenFromCodeRedirect(url: string|URL, params: {redirectUri: string; state?: string; codeVerifier?:string} ): Promise<OAuth2Token> {
const { code } = await this.validateResponse(url, {
state: params.state
});
return this.getToken({
code,
redirectUri: params.redirectUri,
codeVerifier: params.codeVerifier,
});
}
/**

@@ -63,3 +71,3 @@ * After the user redirected back from the authorization endpoint, the

*/
async validateResponse(url: string|URL): Promise<{code: string; codeVerifier?: string}> {
async validateResponse(url: string|URL, params: {state?: string}): Promise<{code: string}> {

@@ -79,4 +87,4 @@ const queryParams = new URL(url).searchParams;

if (this.state !== queryParams.get('state')) {
throw new Error(`The "state" parameter in the url did not match the expected value of ${this.state}`);
if (params.state && params.state !== queryParams.get('state')) {
throw new Error(`The "state" parameter in the url did not match the expected value of ${params.state}`);
}

@@ -94,3 +102,3 @@

*/
async getToken(params: { code: string }): Promise<OAuth2Token> {
async getToken(params: { code: string; redirectUri: string; codeVerifier?: string }): Promise<OAuth2Token> {

@@ -100,5 +108,5 @@ const body:AuthorizationCodeRequest = {

code: params.code,
redirect_uri: this.redirectUri,
redirect_uri: params.redirectUri,
client_id: this.client.settings.clientId,
code_verifier: this.codeVerifier,
code_verifier: params.codeVerifier,
};

@@ -105,0 +113,0 @@ return tokenResponseToOAuth2Token(this.client.request('tokenEndpoint', body));

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

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