@tasoskakour/react-use-oauth2 1.1.0 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # @tasoskakour/react-use-oauth2
2
2
 
3
- ![gh workflow](https://img.shields.io/github/workflow/status/tasoskakour/react-use-oauth2/CI%20&%20CD) [![npm](https://img.shields.io/npm/v/@tasoskakour/react-use-oauth2.svg?style=svg&logo=npm&label=)](https://www.npmjs.com/package/@tasoskakour/react-use-oauth2)
3
+ ![gh workflow](https://img.shields.io/github/actions/workflow/status/tasoskakour/react-use-oauth2/ci-cd.yml?branch=master) [![npm](https://img.shields.io/npm/v/@tasoskakour/react-use-oauth2.svg?style=svg&logo=npm&label=)](https://www.npmjs.com/package/@tasoskakour/react-use-oauth2)
4
4
 
5
5
  > 💎 A custom React hook that makes OAuth2 authorization simple. Both for **Implicit Grant** and **Authorization Code** flows.
6
6
 
@@ -35,7 +35,7 @@ import { OAuth2Popup, useOAuth2 } from "@tasoskakour/react-use-oauth2";
35
35
  import { BrowserRouter, Routes, Route } from "react-router-dom";
36
36
 
37
37
  const Home = () => {
38
- const { data, loading, error, getAuth } = useOAuth2({
38
+ const { data, loading, error, getAuth, logout } = useOAuth2({
39
39
  authorizeUrl: "https://example.com/auth",
40
40
  clientId: "YOUR_CLIENT_ID",
41
41
  redirectUri: `${document.location.origin}/callback`,
@@ -58,7 +58,12 @@ const Home = () => {
58
58
  }
59
59
 
60
60
  if (isLoggedIn) {
61
- return <pre>{JSON.stringify(data)}</pre>;
61
+ return (
62
+ <div>
63
+ <pre>{JSON.stringify(data)}</pre>
64
+ <button onClick={logout}>Logout</button>
65
+ </div>
66
+ )
62
67
  }
63
68
 
64
69
  return (
@@ -124,6 +129,8 @@ This is the hook that makes this package to work. `Options` is an object that co
124
129
  - **loading** (boolean): Is set to true while the authorization is taking place.
125
130
  - **error** (string): Is set when an error occurs.
126
131
  - **getAuth** (function): Call this function to trigger the authorization flow.
132
+ - **logout** (function): Call this function to logout and clear all authorization data.
133
+ - **isPersistent** (boolean): Property that returns false if localStorage is throwing an error and the data is stored only in-memory. Useful if you want to notify the user.
127
134
 
128
135
  ---
129
136
 
package/dist/cjs/index.js CHANGED
@@ -1 +1 @@
1
- "use strict";var e=require("react/jsx-runtime"),t=require("react"),r=function(){return r=Object.assign||function(e){for(var t,r=1,n=arguments.length;r<n;r++)for(var o in t=arguments[r])Object.prototype.hasOwnProperty.call(t,o)&&(e[o]=t[o]);return e},r.apply(this,arguments)};function n(e,t,r,n){return new(r||(r=Promise))((function(o,a){function i(e){try{u(n.next(e))}catch(e){a(e)}}function c(e){try{u(n.throw(e))}catch(e){a(e)}}function u(e){var t;e.done?o(e.value):(t=e.value,t instanceof r?t:new r((function(e){e(t)}))).then(i,c)}u((n=n.apply(e,t||[])).next())}))}function o(e,t){var r,n,o,a,i={label:0,sent:function(){if(1&o[0])throw o[1];return o[1]},trys:[],ops:[]};return a={next:c(0),throw:c(1),return:c(2)},"function"==typeof Symbol&&(a[Symbol.iterator]=function(){return this}),a;function c(c){return function(u){return function(c){if(r)throw new TypeError("Generator is already executing.");for(;a&&(a=0,c[0]&&(i=0)),i;)try{if(r=1,n&&(o=2&c[0]?n.return:c[0]?n.throw||((o=n.return)&&o.call(n),0):n.next)&&!(o=o.call(n,c[1])).done)return o;switch(n=0,o&&(c=[2&c[0],o.value]),c[0]){case 0:case 1:o=c;break;case 4:return i.label++,{value:c[1],done:!1};case 5:i.label++,n=c[1],c=[0];continue;case 7:c=i.ops.pop(),i.trys.pop();continue;default:if(!(o=i.trys,(o=o.length>0&&o[o.length-1])||6!==c[0]&&2!==c[0])){i=0;continue}if(3===c[0]&&(!o||c[1]>o[0]&&c[1]<o[3])){i.label=c[1];break}if(6===c[0]&&i.label<o[1]){i.label=o[1],o=c;break}if(o&&i.label<o[2]){i.label=o[2],i.ops.push(c);break}o[2]&&i.ops.pop(),i.trys.pop();continue}c=t.call(e,i)}catch(e){c=[6,e],n=0}finally{r=o=0}if(5&c[0])throw c[1];return{value:c[0]?c[1]:void 0,done:!0}}([c,u])}}}var a="react-use-oauth2-state-key",i="react-use-oauth2-response",c=function(e){return new URLSearchParams(e).toString()},u=function(e){var t=new URLSearchParams(e);return Object.fromEntries(t.entries())};const s=new Map;function l(e,r){if(void 0===t.useSyncExternalStore)throw new TypeError('You are using React 17 or below. Install with "npm install use-local-storage-state@17".');const[n]=t.useState(null==r?void 0:r.defaultValue);if("undefined"==typeof window)return[n,()=>{},{isPersistent:!0,removeItem:()=>{}}];const o=null==r?void 0:r.serializer;return function(e,r,n=!0,o=p,a=JSON.stringify){if(!s.has(e)&&void 0!==r&&null===localStorage.getItem(e))try{localStorage.setItem(e,a(r))}catch(e){}const i=t.useRef({item:null,parsed:r}),c=t.useSyncExternalStore(t.useCallback((t=>{const r=r=>{e===r&&t()};return d.add(r),()=>{d.delete(r)}}),[e]),(()=>{const t=localStorage.getItem(e);if(s.has(e))i.current={item:t,parsed:s.get(e)};else if(t!==i.current.item){let e;try{e=null===t?r:o(t)}catch(t){e=r}i.current={item:t,parsed:e}}return i.current.parsed}),(()=>r)),u=t.useCallback((t=>{const r=t instanceof Function?t(i.current.parsed):t;try{localStorage.setItem(e,a(r)),s.delete(e)}catch(t){s.set(e,r)}f(e)}),[e,a]);return t.useEffect((()=>{if(!n)return;const t=t=>{t.storageArea===localStorage&&t.key===e&&f(e)};return window.addEventListener("storage",t),()=>window.removeEventListener("storage",t)}),[e,n]),t.useMemo((()=>[c,u,{isPersistent:c===r||!s.has(e),removeItem(){s.delete(e),localStorage.removeItem(e),f(e)}}]),[e,u,c,r])}(e,n,null==r?void 0:r.storageSync,null==o?void 0:o.parse,null==o?void 0:o.stringify)}const d=new Set;function f(e){for(const t of[...d])t(e)}function p(e){return"undefined"===e?void 0:JSON.parse(e)}var v=function(){sessionStorage.removeItem(a)},w=function(e,t,n,o,a){var i=e.split("?")[0],s=u(e.split("?")[1]);return"".concat(i,"?").concat(c(r(r({},s),{client_id:t,grant_type:"authorization_code",code:n,redirect_uri:o,state:a})))};exports.OAuthPopup=function(n){var o=n.Component,c=void 0===o?e.jsx("div",r({style:{margin:"12px"},"data-testid":"popup-loading"},{children:"Loading..."})):o;return t.useEffect((function(){var e,t=r(r({},u(window.location.search.split("?")[1])),u(window.location.hash.split("#")[1])),n=null==t?void 0:t.state,o=null==t?void 0:t.error;if(!window.opener)throw new Error("No window opener");o?window.opener.postMessage({type:i,error:decodeURI(o)||"OAuth error: An error has occured."}):n&&(e=n,sessionStorage.getItem(a)===e)?window.opener.postMessage({type:i,payload:t}):window.opener.postMessage({type:i,error:"OAuth error: State mismatch."})}),[]),c},exports.useOAuth2=function(e){var u=e.authorizeUrl,s=e.clientId,d=e.redirectUri,f=e.scope,p=void 0===f?"":f,h=e.responseType,g=e.extraQueryParameters,m=void 0===g?{}:g,y=e.onSuccess,S=e.onError,b=t.useRef(m),I=t.useRef(),E=t.useRef(),x=t.useState({loading:!1,error:null}),k=x[0],O=k.loading,P=k.error,A=x[1],L=l("".concat(h,"-").concat(u,"-").concat(s,"-").concat(p),{defaultValue:null}),R=L[0],C=L[1],U="code"===h&&e.exchangeCodeForTokenServerURL,j="code"===h&&e.exchangeCodeForTokenMethod,M=t.useCallback((function(){A({loading:!0,error:null});var e,t,l,f,g,m=(e="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",t=new Uint8Array(40),window.crypto.getRandomValues(t),t=t.map((function(t){return e.codePointAt(t%e.length)})),String.fromCharCode.apply(null,t));function x(e){var t,r,a;return n(this,void 0,void 0,(function(){var n,c,u;return o(this,(function(o){switch(o.label){case 0:if((null===(t=null==e?void 0:e.data)||void 0===t?void 0:t.type)!==i)return[2];o.label=1;case 1:return o.trys.push([1,10,11,12]),(n=null===(r=null==e?void 0:e.data)||void 0===r?void 0:r.error)?(A({loading:!1,error:n||"Unknown Error"}),S?[4,S(n)]:[3,3]):[3,4];case 2:o.sent(),o.label=3;case 3:return[3,9];case 4:return c=null===(a=null==e?void 0:e.data)||void 0===a?void 0:a.payload,"code"===h&&U?[4,fetch(w(U,s,null==c?void 0:c.code,d,m),{method:j||"POST"})]:[3,7];case 5:return[4,o.sent().json()];case 6:c=o.sent(),o.label=7;case 7:return A({loading:!1,error:null}),C(c),y?[4,y(c)]:[3,9];case 8:o.sent(),o.label=9;case 9:return[3,12];case 10:return u=o.sent(),console.error(u),A({loading:!1,error:u.toString()}),[3,12];case 11:return function(e,t,r){clearInterval(e.current),function(e){var t;null===(t=e.current)||void 0===t||t.close()}(t),v(),window.removeEventListener("message",r)}(E,I,x),[7];case 12:return[2]}}))}))}return function(e){sessionStorage.setItem(a,e)}(m),I.current=(l=function(e,t,n,o,a,i,u){var s=c(r({response_type:i,client_id:t,redirect_uri:n,scope:o,state:a},u.current));return"".concat(e,"?").concat(s)}(u,s,d,p,m,h,b),f=window.outerHeight/2+window.screenY-350,g=window.outerWidth/2+window.screenX-300,window.open(l,"OAuth2 Popup","height=".concat(700,",width=").concat(600,",top=").concat(f,",left=").concat(g))),window.addEventListener("message",x),E.current=setInterval((function(){var e,t,n;(!(null===(e=I.current)||void 0===e?void 0:e.window)||(null===(n=null===(t=I.current)||void 0===t?void 0:t.window)||void 0===n?void 0:n.closed))&&(A((function(e){return r(r({},e),{loading:!1})})),console.warn("Warning: Popup was closed before completing authentication."),clearInterval(E.current),v(),window.removeEventListener("message",x))}),250),function(){window.removeEventListener("message",x),E.current&&clearInterval(E.current)}}),[u,s,d,p,h,U,j,y,S,A,C]);return{data:R,loading:O,error:P,getAuth:M}};
1
+ "use strict";var e=require("react/jsx-runtime"),r=require("react"),t=function(){return t=Object.assign||function(e){for(var r,t=1,n=arguments.length;t<n;t++)for(var o in r=arguments[t])Object.prototype.hasOwnProperty.call(r,o)&&(e[o]=r[o]);return e},t.apply(this,arguments)};function n(e,r,t,n){return new(t||(t=Promise))((function(o,a){function i(e){try{u(n.next(e))}catch(e){a(e)}}function c(e){try{u(n.throw(e))}catch(e){a(e)}}function u(e){var r;e.done?o(e.value):(r=e.value,r instanceof t?r:new t((function(e){e(r)}))).then(i,c)}u((n=n.apply(e,r||[])).next())}))}function o(e,r){var t,n,o,a,i={label:0,sent:function(){if(1&o[0])throw o[1];return o[1]},trys:[],ops:[]};return a={next:c(0),throw:c(1),return:c(2)},"function"==typeof Symbol&&(a[Symbol.iterator]=function(){return this}),a;function c(c){return function(u){return function(c){if(t)throw new TypeError("Generator is already executing.");for(;a&&(a=0,c[0]&&(i=0)),i;)try{if(t=1,n&&(o=2&c[0]?n.return:c[0]?n.throw||((o=n.return)&&o.call(n),0):n.next)&&!(o=o.call(n,c[1])).done)return o;switch(n=0,o&&(c=[2&c[0],o.value]),c[0]){case 0:case 1:o=c;break;case 4:return i.label++,{value:c[1],done:!1};case 5:i.label++,n=c[1],c=[0];continue;case 7:c=i.ops.pop(),i.trys.pop();continue;default:if(!(o=i.trys,(o=o.length>0&&o[o.length-1])||6!==c[0]&&2!==c[0])){i=0;continue}if(3===c[0]&&(!o||c[1]>o[0]&&c[1]<o[3])){i.label=c[1];break}if(6===c[0]&&i.label<o[1]){i.label=o[1],o=c;break}if(o&&i.label<o[2]){i.label=o[2],i.ops.push(c);break}o[2]&&i.ops.pop(),i.trys.pop();continue}c=r.call(e,i)}catch(e){c=[6,e],n=0}finally{t=o=0}if(5&c[0])throw c[1];return{value:c[0]?c[1]:void 0,done:!0}}([c,u])}}}var a="react-use-oauth2-state-key",i="react-use-oauth2-response",c=function(e){return new URLSearchParams(e).toString()},u=function(e){var r=new URLSearchParams(e);return Object.fromEntries(r.entries())},s=function(e,r){return e.postMessage(r)},l=function(e,r,t){clearInterval(e.current),r.current&&"function"==typeof r.current.close&&function(e){var r;null===(r=e.current)||void 0===r||r.close()}(r),sessionStorage.removeItem(a),window.removeEventListener("message",t)},d=function(e,r,n,o,a){var i=e.split("?")[0],s=u(e.split("?")[1]);return"".concat(i,"?").concat(c(t(t({},s),{client_id:r,grant_type:"authorization_code",code:n,redirect_uri:o,state:a})))};const f=new Map;function p(e,t){if(void 0===r.useSyncExternalStore)throw new TypeError('You are using React 17 or below. Install with "npm install use-local-storage-state@17".');const[n]=r.useState(null==t?void 0:t.defaultValue);if("undefined"==typeof window)return[n,()=>{},{isPersistent:!0,removeItem:()=>{}}];const o=null==t?void 0:t.serializer;return function(e,t,n=!0,o=w,a=JSON.stringify){if(!f.has(e)&&void 0!==t&&null===localStorage.getItem(e))try{localStorage.setItem(e,a(t))}catch(e){}const i=r.useRef({item:null,parsed:t}),c=r.useSyncExternalStore(r.useCallback((r=>{const t=t=>{e===t&&r()};return v.add(t),()=>{v.delete(t)}}),[e]),(()=>{const r=localStorage.getItem(e);if(f.has(e))i.current={item:r,parsed:f.get(e)};else if(r!==i.current.item){let e;try{e=null===r?t:o(r)}catch(r){e=t}i.current={item:r,parsed:e}}return i.current.parsed}),(()=>t)),u=r.useCallback((r=>{const t=r instanceof Function?r(i.current.parsed):r;try{localStorage.setItem(e,a(t)),f.delete(e)}catch(r){f.set(e,t)}h(e)}),[e,a]);return r.useEffect((()=>{if(!n)return;const r=r=>{r.storageArea===localStorage&&r.key===e&&h(e)};return window.addEventListener("storage",r),()=>window.removeEventListener("storage",r)}),[e,n]),r.useMemo((()=>[c,u,{isPersistent:c===t||!f.has(e),removeItem(){f.delete(e),localStorage.removeItem(e),h(e)}}]),[e,u,c,t])}(e,n,null==t?void 0:t.storageSync,null==o?void 0:o.parse,null==o?void 0:o.stringify)}const v=new Set;function h(e){for(const r of[...v])r(e)}function w(e){return"undefined"===e?void 0:JSON.parse(e)}exports.OAuthPopup=function(n){var o=n.Component,c=void 0===o?e.jsx("div",t({style:{margin:"12px"},"data-testid":"popup-loading"},{children:"Loading..."})):o;return r.useEffect((function(){var e=t(t({},u(window.location.search.split("?")[1])),u(window.location.hash.split("#")[1])),r=null==e?void 0:e.state,n=null==e?void 0:e.error,o=null===window||void 0===window?void 0:window.opener;if(!function(e){return null!=e}(o))throw new Error("No window opener");var c,l=r&&(c=r,sessionStorage.getItem(a)===c);if(!n&&l)s(o,{type:i,payload:e});else{var d=n?decodeURI(n):l?"OAuth error: An error has occured.":"OAuth error: State mismatch.";s(o,{type:i,error:d})}}),[]),c},exports.useOAuth2=function(e){var u=e.authorizeUrl,s=e.clientId,f=e.redirectUri,v=e.scope,h=void 0===v?"":v,w=e.responseType,g=e.extraQueryParameters,y=void 0===g?{}:g,m=e.onSuccess,S=e.onError;!function(e){var r=e.authorizeUrl,t=e.clientId,n=e.redirectUri,o=e.responseType,a=e.extraQueryParameters,i=void 0===a?{}:a,c=e.onSuccess,u=e.onError;if(!(r&&t&&n&&o))throw new Error("Missing required props for useOAuth2. Required props are: {authorizeUrl, clientId, redirectUri, responseType}");if("code"===o&&!e.exchangeCodeForTokenServerURL)throw new Error('exchangeCodeForTokenServerURL is required for responseType of "code" for useOAuth2.');if("code"===o&&e.exchangeCodeForTokenMethod&&!["POST","GET"].includes(e.exchangeCodeForTokenMethod))throw new Error('Invalid exchangeCodeForTokenServerURL value. It can be one of "POST" or "GET".');if("object"!=typeof i)throw new TypeError("extraQueryParameters must be an object for useOAuth2.");if(c&&"function"!=typeof c)throw new TypeError("onSuccess callback must be a function for useOAuth2.");if(u&&"function"!=typeof u)throw new TypeError("onError callback must be a function for useOAuth2.")}(e);var b=r.useRef(y),E=r.useRef(),x=r.useRef(),I=r.useState({loading:!1,error:null}),T=I[0],k=T.loading,O=T.error,P=I[1],A=p("".concat(w,"-").concat(u,"-").concat(s,"-").concat(h),{defaultValue:null}),U=A[0],C=A[1],R=A[2],L=R.removeItem,j=R.isPersistent,F="code"===w&&e.exchangeCodeForTokenServerURL,M="code"===w&&e.exchangeCodeForTokenMethod,_=r.useCallback((function(){P({loading:!0,error:null});var e,r,p,v,g,y=(e="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",r=new Uint8Array(40),window.crypto.getRandomValues(r),r=r.map((function(r){return e.codePointAt(r%e.length)})),String.fromCharCode.apply(null,r));function I(e){var r,t,a;return n(this,void 0,void 0,(function(){var n,c,u;return o(this,(function(o){switch(o.label){case 0:if((null===(r=null==e?void 0:e.data)||void 0===r?void 0:r.type)!==i)return[2];o.label=1;case 1:return o.trys.push([1,10,11,12]),"error"in e.data?(n=(null===(t=e.data)||void 0===t?void 0:t.error)||"Unknown Error occured.",P({loading:!1,error:n}),S?[4,S(n)]:[3,3]):[3,4];case 2:o.sent(),o.label=3;case 3:return[3,9];case 4:return c=null===(a=null==e?void 0:e.data)||void 0===a?void 0:a.payload,"code"===w&&F?[4,fetch(d(F,s,null==c?void 0:c.code,f,y),{method:M||"POST"})]:[3,7];case 5:return[4,o.sent().json()];case 6:c=o.sent(),o.label=7;case 7:return P({loading:!1,error:null}),C(c),m?[4,m(c)]:[3,9];case 8:o.sent(),o.label=9;case 9:return[3,12];case 10:return u=o.sent(),console.error(u),P({loading:!1,error:u.toString()}),[3,12];case 11:return l(x,E,I),[7];case 12:return[2]}}))}))}return function(e){sessionStorage.setItem(a,e)}(y),E.current=(p=function(e,r,n,o,a,i,u){void 0===u&&(u={});var s=c(t({response_type:i,client_id:r,redirect_uri:n,scope:o,state:a},u));return"".concat(e,"?").concat(s)}(u,s,f,h,y,w,b.current),v=window.outerHeight/2+window.screenY-350,g=window.outerWidth/2+window.screenX-300,window.open(p,"OAuth2 Popup","height=".concat(700,",width=").concat(600,",top=").concat(v,",left=").concat(g))),window.addEventListener("message",I),x.current=setInterval((function(){var e,r,n;(!(null===(e=E.current)||void 0===e?void 0:e.window)||(null===(n=null===(r=E.current)||void 0===r?void 0:r.window)||void 0===n?void 0:n.closed))&&(P((function(e){return t(t({},e),{loading:!1})})),console.warn("Warning: Popup was closed before completing authentication."),l(x,E,I))}),250),function(){window.removeEventListener("message",I),x.current&&clearInterval(x.current)}}),[u,s,f,h,w,F,M,m,S,P,C]);return{data:U,loading:k,error:O,getAuth:_,logout:r.useCallback((function(){L(),P({loading:!1,error:null})}),[L]),isPersistent:j}};
@@ -2,5 +2,5 @@
2
2
  type Props = {
3
3
  Component?: React.ReactElement;
4
4
  };
5
- declare const OAuthPopup: (props: Props) => JSX.Element;
6
- export default OAuthPopup;
5
+ export declare const OAuthPopup: ({ Component, }: Props) => import("react").ReactElement<any, string | import("react").JSXElementConstructor<any>>;
6
+ export {};
@@ -1,2 +1,3 @@
1
- export { default as OAuthPopup } from './OAuthPopup';
2
- export { default as useOAuth2, Oauth2Props } from './use-oauth2';
1
+ export * from './OAuthPopup';
2
+ export * from './use-oauth2';
3
+ export * from './types';
@@ -1,4 +1,16 @@
1
+ import { TMessageData, TOauth2Props } from './types';
1
2
  export declare const objectToQuery: (object: Record<string, string>) => string;
2
3
  export declare const queryToObject: (query: string) => {
3
4
  [k: string]: string;
4
5
  };
6
+ export declare const formatAuthorizeUrl: (authorizeUrl: string, clientId: string, redirectUri: string, scope: string, state: string, responseType: TOauth2Props['responseType'], extraQueryParameters?: TOauth2Props['extraQueryParameters']) => string;
7
+ export declare const generateState: () => string;
8
+ export declare const saveState: (state: string) => void;
9
+ export declare const removeState: () => void;
10
+ export declare const checkState: (receivedState: string) => boolean;
11
+ export declare const openPopup: (url: string) => Window | null;
12
+ export declare const closePopup: (popupRef: React.MutableRefObject<Window | null | undefined>) => void;
13
+ export declare const isWindowOpener: (opener: Window | null) => opener is Window;
14
+ export declare const openerPostMessage: (opener: Window, message: TMessageData) => void;
15
+ export declare const cleanup: (intervalRef: React.MutableRefObject<string | number | NodeJS.Timeout | undefined>, popupRef: React.MutableRefObject<Window | null | undefined>, handleMessageListener: any) => void;
16
+ export declare const formatExchangeCodeForTokenServerURL: (exchangeCodeForTokenServerURL: string, clientId: string, code: string, redirectUri: string, state: string) => string;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,33 @@
1
+ import { OAUTH_RESPONSE } from './constants';
2
+ export type TAuthTokenPayload = {
3
+ token_type: string;
4
+ expires_in: number;
5
+ access_token: string;
6
+ scope: string;
7
+ refresh_token: string;
8
+ };
9
+ export type TResponseTypeBasedProps<TData> = {
10
+ responseType: 'code';
11
+ exchangeCodeForTokenServerURL: string;
12
+ exchangeCodeForTokenMethod?: 'POST' | 'GET';
13
+ onSuccess?: (payload: TData) => void;
14
+ } | {
15
+ responseType: 'token';
16
+ onSuccess?: (payload: TData) => void;
17
+ };
18
+ export type TOauth2Props<TData = TAuthTokenPayload> = {
19
+ authorizeUrl: string;
20
+ clientId: string;
21
+ redirectUri: string;
22
+ scope?: string;
23
+ extraQueryParameters?: Record<string, any>;
24
+ onError?: (error: string) => void;
25
+ } & TResponseTypeBasedProps<TData>;
26
+ export type TState<TData = TAuthTokenPayload> = TData | null;
27
+ export type TMessageData = {
28
+ type: typeof OAUTH_RESPONSE;
29
+ error: string;
30
+ } | {
31
+ type: typeof OAUTH_RESPONSE;
32
+ payload: any;
33
+ };
@@ -0,0 +1,2 @@
1
+ import { TAuthTokenPayload, TOauth2Props } from './types';
2
+ export declare const useCheckProps: <TData = TAuthTokenPayload>(props: TOauth2Props<TData>) => void;
@@ -0,0 +1 @@
1
+ export {};
@@ -1,32 +1,9 @@
1
- export type AuthTokenPayload = {
2
- token_type: string;
3
- expires_in: number;
4
- access_token: string;
5
- scope: string;
6
- refresh_token: string;
7
- };
8
- export type ResponseTypeBasedProps<TData> = {
9
- responseType: 'code';
10
- exchangeCodeForTokenServerURL: string;
11
- exchangeCodeForTokenMethod?: 'POST' | 'GET';
12
- onSuccess?: (payload: TData) => void;
13
- } | {
14
- responseType: 'token';
15
- onSuccess?: (payload: TData) => void;
16
- };
17
- export type Oauth2Props<TData = AuthTokenPayload> = {
18
- authorizeUrl: string;
19
- clientId: string;
20
- redirectUri: string;
21
- scope?: string;
22
- extraQueryParameters?: Record<string, any>;
23
- onError?: (error: string) => void;
24
- } & ResponseTypeBasedProps<TData>;
25
- export type State<TData = AuthTokenPayload> = TData | null;
26
- declare const useOAuth2: <TData = AuthTokenPayload>(props: Oauth2Props<TData>) => {
27
- data: State<AuthTokenPayload>;
1
+ import { TAuthTokenPayload, TOauth2Props, TState } from './types';
2
+ export declare const useOAuth2: <TData = TAuthTokenPayload>(props: TOauth2Props<TData>) => {
3
+ data: TState;
28
4
  loading: boolean;
29
- error: null;
5
+ error: string | null;
30
6
  getAuth: () => () => void;
7
+ logout: () => void;
8
+ isPersistent: boolean;
31
9
  };
32
- export default useOAuth2;
@@ -0,0 +1 @@
1
+ export {};
package/dist/esm/index.js CHANGED
@@ -1 +1 @@
1
- import{jsx as e}from"react/jsx-runtime";import{useEffect as r,useSyncExternalStore as n,useState as t,useRef as o,useCallback as a,useMemo as i}from"react";var c=function(){return c=Object.assign||function(e){for(var r,n=1,t=arguments.length;n<t;n++)for(var o in r=arguments[n])Object.prototype.hasOwnProperty.call(r,o)&&(e[o]=r[o]);return e},c.apply(this,arguments)};function l(e,r,n,t){return new(n||(n=Promise))((function(o,a){function i(e){try{l(t.next(e))}catch(e){a(e)}}function c(e){try{l(t.throw(e))}catch(e){a(e)}}function l(e){var r;e.done?o(e.value):(r=e.value,r instanceof n?r:new n((function(e){e(r)}))).then(i,c)}l((t=t.apply(e,r||[])).next())}))}function u(e,r){var n,t,o,a,i={label:0,sent:function(){if(1&o[0])throw o[1];return o[1]},trys:[],ops:[]};return a={next:c(0),throw:c(1),return:c(2)},"function"==typeof Symbol&&(a[Symbol.iterator]=function(){return this}),a;function c(c){return function(l){return function(c){if(n)throw new TypeError("Generator is already executing.");for(;a&&(a=0,c[0]&&(i=0)),i;)try{if(n=1,t&&(o=2&c[0]?t.return:c[0]?t.throw||((o=t.return)&&o.call(t),0):t.next)&&!(o=o.call(t,c[1])).done)return o;switch(t=0,o&&(c=[2&c[0],o.value]),c[0]){case 0:case 1:o=c;break;case 4:return i.label++,{value:c[1],done:!1};case 5:i.label++,t=c[1],c=[0];continue;case 7:c=i.ops.pop(),i.trys.pop();continue;default:if(!(o=i.trys,(o=o.length>0&&o[o.length-1])||6!==c[0]&&2!==c[0])){i=0;continue}if(3===c[0]&&(!o||c[1]>o[0]&&c[1]<o[3])){i.label=c[1];break}if(6===c[0]&&i.label<o[1]){i.label=o[1],o=c;break}if(o&&i.label<o[2]){i.label=o[2],i.ops.push(c);break}o[2]&&i.ops.pop(),i.trys.pop();continue}c=r.call(e,i)}catch(e){c=[6,e],t=0}finally{n=o=0}if(5&c[0])throw c[1];return{value:c[0]?c[1]:void 0,done:!0}}([c,l])}}}var s="react-use-oauth2-state-key",d="react-use-oauth2-response",p=function(e){return new URLSearchParams(e).toString()},f=function(e){var r=new URLSearchParams(e);return Object.fromEntries(r.entries())},v=function(n){var t=n.Component,o=void 0===t?e("div",c({style:{margin:"12px"},"data-testid":"popup-loading"},{children:"Loading..."})):t;return r((function(){var e,r=c(c({},f(window.location.search.split("?")[1])),f(window.location.hash.split("#")[1])),n=null==r?void 0:r.state,t=null==r?void 0:r.error;if(!window.opener)throw new Error("No window opener");t?window.opener.postMessage({type:d,error:decodeURI(t)||"OAuth error: An error has occured."}):n&&(e=n,sessionStorage.getItem(s)===e)?window.opener.postMessage({type:d,payload:r}):window.opener.postMessage({type:d,error:"OAuth error: State mismatch."})}),[]),o};const w=new Map;function h(e,c){if(void 0===n)throw new TypeError('You are using React 17 or below. Install with "npm install use-local-storage-state@17".');const[l]=t(null==c?void 0:c.defaultValue);if("undefined"==typeof window)return[l,()=>{},{isPersistent:!0,removeItem:()=>{}}];const u=null==c?void 0:c.serializer;return function(e,t,c=!0,l=y,u=JSON.stringify){if(!w.has(e)&&void 0!==t&&null===localStorage.getItem(e))try{localStorage.setItem(e,u(t))}catch(e){}const s=o({item:null,parsed:t}),d=n(a((r=>{const n=n=>{e===n&&r()};return g.add(n),()=>{g.delete(n)}}),[e]),(()=>{const r=localStorage.getItem(e);if(w.has(e))s.current={item:r,parsed:w.get(e)};else if(r!==s.current.item){let e;try{e=null===r?t:l(r)}catch(r){e=t}s.current={item:r,parsed:e}}return s.current.parsed}),(()=>t)),p=a((r=>{const n=r instanceof Function?r(s.current.parsed):r;try{localStorage.setItem(e,u(n)),w.delete(e)}catch(r){w.set(e,n)}m(e)}),[e,u]);return r((()=>{if(!c)return;const r=r=>{r.storageArea===localStorage&&r.key===e&&m(e)};return window.addEventListener("storage",r),()=>window.removeEventListener("storage",r)}),[e,c]),i((()=>[d,p,{isPersistent:d===t||!w.has(e),removeItem(){w.delete(e),localStorage.removeItem(e),m(e)}}]),[e,p,d,t])}(e,l,null==c?void 0:c.storageSync,null==u?void 0:u.parse,null==u?void 0:u.stringify)}const g=new Set;function m(e){for(const r of[...g])r(e)}function y(e){return"undefined"===e?void 0:JSON.parse(e)}var b=function(){sessionStorage.removeItem(s)},S=function(e,r,n,t,o){var a=e.split("?")[0],i=f(e.split("?")[1]);return"".concat(a,"?").concat(p(c(c({},i),{client_id:r,grant_type:"authorization_code",code:n,redirect_uri:t,state:o})))},I=function(e){var r=e.authorizeUrl,n=e.clientId,i=e.redirectUri,f=e.scope,v=void 0===f?"":f,w=e.responseType,g=e.extraQueryParameters,m=void 0===g?{}:g,y=e.onSuccess,I=e.onError,E=o(m),x=o(),P=o(),L=t({loading:!1,error:null}),O=L[0],k=O.loading,A=O.error,U=L[1],R=h("".concat(w,"-").concat(r,"-").concat(n,"-").concat(v),{defaultValue:null}),T=R[0],_=R[1],j="code"===w&&e.exchangeCodeForTokenServerURL,C="code"===w&&e.exchangeCodeForTokenMethod,M=a((function(){U({loading:!0,error:null});var e,t,o,a,f,h=(e="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",t=new Uint8Array(40),window.crypto.getRandomValues(t),t=t.map((function(r){return e.codePointAt(r%e.length)})),String.fromCharCode.apply(null,t));function g(e){var r,t,o;return l(this,void 0,void 0,(function(){var a,c,l;return u(this,(function(u){switch(u.label){case 0:if((null===(r=null==e?void 0:e.data)||void 0===r?void 0:r.type)!==d)return[2];u.label=1;case 1:return u.trys.push([1,10,11,12]),(a=null===(t=null==e?void 0:e.data)||void 0===t?void 0:t.error)?(U({loading:!1,error:a||"Unknown Error"}),I?[4,I(a)]:[3,3]):[3,4];case 2:u.sent(),u.label=3;case 3:return[3,9];case 4:return c=null===(o=null==e?void 0:e.data)||void 0===o?void 0:o.payload,"code"===w&&j?[4,fetch(S(j,n,null==c?void 0:c.code,i,h),{method:C||"POST"})]:[3,7];case 5:return[4,u.sent().json()];case 6:c=u.sent(),u.label=7;case 7:return U({loading:!1,error:null}),_(c),y?[4,y(c)]:[3,9];case 8:u.sent(),u.label=9;case 9:return[3,12];case 10:return l=u.sent(),console.error(l),U({loading:!1,error:l.toString()}),[3,12];case 11:return function(e,r,n){clearInterval(e.current),function(e){var r;null===(r=e.current)||void 0===r||r.close()}(r),b(),window.removeEventListener("message",n)}(P,x,g),[7];case 12:return[2]}}))}))}return function(e){sessionStorage.setItem(s,e)}(h),x.current=(o=function(e,r,n,t,o,a,i){var l=p(c({response_type:a,client_id:r,redirect_uri:n,scope:t,state:o},i.current));return"".concat(e,"?").concat(l)}(r,n,i,v,h,w,E),a=window.outerHeight/2+window.screenY-350,f=window.outerWidth/2+window.screenX-300,window.open(o,"OAuth2 Popup","height=".concat(700,",width=").concat(600,",top=").concat(a,",left=").concat(f))),window.addEventListener("message",g),P.current=setInterval((function(){var e,r,n;(!(null===(e=x.current)||void 0===e?void 0:e.window)||(null===(n=null===(r=x.current)||void 0===r?void 0:r.window)||void 0===n?void 0:n.closed))&&(U((function(e){return c(c({},e),{loading:!1})})),console.warn("Warning: Popup was closed before completing authentication."),clearInterval(P.current),b(),window.removeEventListener("message",g))}),250),function(){window.removeEventListener("message",g),P.current&&clearInterval(P.current)}}),[r,n,i,v,w,j,C,y,I,U,_]);return{data:T,loading:k,error:A,getAuth:M}};export{v as OAuthPopup,I as useOAuth2};
1
+ import{jsx as e}from"react/jsx-runtime";import{useEffect as r,useSyncExternalStore as n,useState as t,useRef as o,useCallback as i,useMemo as a}from"react";var c=function(){return c=Object.assign||function(e){for(var r,n=1,t=arguments.length;n<t;n++)for(var o in r=arguments[n])Object.prototype.hasOwnProperty.call(r,o)&&(e[o]=r[o]);return e},c.apply(this,arguments)};function u(e,r,n,t){return new(n||(n=Promise))((function(o,i){function a(e){try{u(t.next(e))}catch(e){i(e)}}function c(e){try{u(t.throw(e))}catch(e){i(e)}}function u(e){var r;e.done?o(e.value):(r=e.value,r instanceof n?r:new n((function(e){e(r)}))).then(a,c)}u((t=t.apply(e,r||[])).next())}))}function s(e,r){var n,t,o,i,a={label:0,sent:function(){if(1&o[0])throw o[1];return o[1]},trys:[],ops:[]};return i={next:c(0),throw:c(1),return:c(2)},"function"==typeof Symbol&&(i[Symbol.iterator]=function(){return this}),i;function c(c){return function(u){return function(c){if(n)throw new TypeError("Generator is already executing.");for(;i&&(i=0,c[0]&&(a=0)),a;)try{if(n=1,t&&(o=2&c[0]?t.return:c[0]?t.throw||((o=t.return)&&o.call(t),0):t.next)&&!(o=o.call(t,c[1])).done)return o;switch(t=0,o&&(c=[2&c[0],o.value]),c[0]){case 0:case 1:o=c;break;case 4:return a.label++,{value:c[1],done:!1};case 5:a.label++,t=c[1],c=[0];continue;case 7:c=a.ops.pop(),a.trys.pop();continue;default:if(!(o=a.trys,(o=o.length>0&&o[o.length-1])||6!==c[0]&&2!==c[0])){a=0;continue}if(3===c[0]&&(!o||c[1]>o[0]&&c[1]<o[3])){a.label=c[1];break}if(6===c[0]&&a.label<o[1]){a.label=o[1],o=c;break}if(o&&a.label<o[2]){a.label=o[2],a.ops.push(c);break}o[2]&&a.ops.pop(),a.trys.pop();continue}c=r.call(e,a)}catch(e){c=[6,e],t=0}finally{n=o=0}if(5&c[0])throw c[1];return{value:c[0]?c[1]:void 0,done:!0}}([c,u])}}}var l="react-use-oauth2-state-key",d="react-use-oauth2-response",f=function(e){return new URLSearchParams(e).toString()},p=function(e){var r=new URLSearchParams(e);return Object.fromEntries(r.entries())},v=function(e,r){return e.postMessage(r)},h=function(e,r,n){clearInterval(e.current),r.current&&"function"==typeof r.current.close&&function(e){var r;null===(r=e.current)||void 0===r||r.close()}(r),sessionStorage.removeItem(l),window.removeEventListener("message",n)},w=function(e,r,n,t,o){var i=e.split("?")[0],a=p(e.split("?")[1]);return"".concat(i,"?").concat(f(c(c({},a),{client_id:r,grant_type:"authorization_code",code:n,redirect_uri:t,state:o})))},g=function(n){var t=n.Component,o=void 0===t?e("div",c({style:{margin:"12px"},"data-testid":"popup-loading"},{children:"Loading..."})):t;return r((function(){var e=c(c({},p(window.location.search.split("?")[1])),p(window.location.hash.split("#")[1])),r=null==e?void 0:e.state,n=null==e?void 0:e.error,t=null===window||void 0===window?void 0:window.opener;if(!function(e){return null!=e}(t))throw new Error("No window opener");var o,i=r&&(o=r,sessionStorage.getItem(l)===o);if(!n&&i)v(t,{type:d,payload:e});else{var a=n?decodeURI(n):i?"OAuth error: An error has occured.":"OAuth error: State mismatch.";v(t,{type:d,error:a})}}),[]),o};const m=new Map;function y(e,c){if(void 0===n)throw new TypeError('You are using React 17 or below. Install with "npm install use-local-storage-state@17".');const[u]=t(null==c?void 0:c.defaultValue);if("undefined"==typeof window)return[u,()=>{},{isPersistent:!0,removeItem:()=>{}}];const s=null==c?void 0:c.serializer;return function(e,t,c=!0,u=E,s=JSON.stringify){if(!m.has(e)&&void 0!==t&&null===localStorage.getItem(e))try{localStorage.setItem(e,s(t))}catch(e){}const l=o({item:null,parsed:t}),d=n(i((r=>{const n=n=>{e===n&&r()};return b.add(n),()=>{b.delete(n)}}),[e]),(()=>{const r=localStorage.getItem(e);if(m.has(e))l.current={item:r,parsed:m.get(e)};else if(r!==l.current.item){let e;try{e=null===r?t:u(r)}catch(r){e=t}l.current={item:r,parsed:e}}return l.current.parsed}),(()=>t)),f=i((r=>{const n=r instanceof Function?r(l.current.parsed):r;try{localStorage.setItem(e,s(n)),m.delete(e)}catch(r){m.set(e,n)}S(e)}),[e,s]);return r((()=>{if(!c)return;const r=r=>{r.storageArea===localStorage&&r.key===e&&S(e)};return window.addEventListener("storage",r),()=>window.removeEventListener("storage",r)}),[e,c]),a((()=>[d,f,{isPersistent:d===t||!m.has(e),removeItem(){m.delete(e),localStorage.removeItem(e),S(e)}}]),[e,f,d,t])}(e,u,null==c?void 0:c.storageSync,null==s?void 0:s.parse,null==s?void 0:s.stringify)}const b=new Set;function S(e){for(const r of[...b])r(e)}function E(e){return"undefined"===e?void 0:JSON.parse(e)}var I=function(e){var r=e.authorizeUrl,n=e.clientId,a=e.redirectUri,p=e.scope,v=void 0===p?"":p,g=e.responseType,m=e.extraQueryParameters,b=void 0===m?{}:m,S=e.onSuccess,E=e.onError;!function(e){var r=e.authorizeUrl,n=e.clientId,t=e.redirectUri,o=e.responseType,i=e.extraQueryParameters,a=void 0===i?{}:i,c=e.onSuccess,u=e.onError;if(!(r&&n&&t&&o))throw new Error("Missing required props for useOAuth2. Required props are: {authorizeUrl, clientId, redirectUri, responseType}");if("code"===o&&!e.exchangeCodeForTokenServerURL)throw new Error('exchangeCodeForTokenServerURL is required for responseType of "code" for useOAuth2.');if("code"===o&&e.exchangeCodeForTokenMethod&&!["POST","GET"].includes(e.exchangeCodeForTokenMethod))throw new Error('Invalid exchangeCodeForTokenServerURL value. It can be one of "POST" or "GET".');if("object"!=typeof a)throw new TypeError("extraQueryParameters must be an object for useOAuth2.");if(c&&"function"!=typeof c)throw new TypeError("onSuccess callback must be a function for useOAuth2.");if(u&&"function"!=typeof u)throw new TypeError("onError callback must be a function for useOAuth2.")}(e);var I=o(b),T=o(),x=o(),O=t({loading:!1,error:null}),P=O[0],k=P.loading,U=P.error,A=O[1],L=y("".concat(g,"-").concat(r,"-").concat(n,"-").concat(v),{defaultValue:null}),C=L[0],R=L[1],F=L[2],j=F.removeItem,M=F.isPersistent,_="code"===g&&e.exchangeCodeForTokenServerURL,z="code"===g&&e.exchangeCodeForTokenMethod,q=i((function(){A({loading:!0,error:null});var e,t,o,i,p,m=(e="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",t=new Uint8Array(40),window.crypto.getRandomValues(t),t=t.map((function(r){return e.codePointAt(r%e.length)})),String.fromCharCode.apply(null,t));function y(e){var r,t,o;return u(this,void 0,void 0,(function(){var i,c,u;return s(this,(function(s){switch(s.label){case 0:if((null===(r=null==e?void 0:e.data)||void 0===r?void 0:r.type)!==d)return[2];s.label=1;case 1:return s.trys.push([1,10,11,12]),"error"in e.data?(i=(null===(t=e.data)||void 0===t?void 0:t.error)||"Unknown Error occured.",A({loading:!1,error:i}),E?[4,E(i)]:[3,3]):[3,4];case 2:s.sent(),s.label=3;case 3:return[3,9];case 4:return c=null===(o=null==e?void 0:e.data)||void 0===o?void 0:o.payload,"code"===g&&_?[4,fetch(w(_,n,null==c?void 0:c.code,a,m),{method:z||"POST"})]:[3,7];case 5:return[4,s.sent().json()];case 6:c=s.sent(),s.label=7;case 7:return A({loading:!1,error:null}),R(c),S?[4,S(c)]:[3,9];case 8:s.sent(),s.label=9;case 9:return[3,12];case 10:return u=s.sent(),console.error(u),A({loading:!1,error:u.toString()}),[3,12];case 11:return h(x,T,y),[7];case 12:return[2]}}))}))}return function(e){sessionStorage.setItem(l,e)}(m),T.current=(o=function(e,r,n,t,o,i,a){void 0===a&&(a={});var u=f(c({response_type:i,client_id:r,redirect_uri:n,scope:t,state:o},a));return"".concat(e,"?").concat(u)}(r,n,a,v,m,g,I.current),i=window.outerHeight/2+window.screenY-350,p=window.outerWidth/2+window.screenX-300,window.open(o,"OAuth2 Popup","height=".concat(700,",width=").concat(600,",top=").concat(i,",left=").concat(p))),window.addEventListener("message",y),x.current=setInterval((function(){var e,r,n;(!(null===(e=T.current)||void 0===e?void 0:e.window)||(null===(n=null===(r=T.current)||void 0===r?void 0:r.window)||void 0===n?void 0:n.closed))&&(A((function(e){return c(c({},e),{loading:!1})})),console.warn("Warning: Popup was closed before completing authentication."),h(x,T,y))}),250),function(){window.removeEventListener("message",y),x.current&&clearInterval(x.current)}}),[r,n,a,v,g,_,z,S,E,A,R]);return{data:C,loading:k,error:U,getAuth:q,logout:i((function(){j(),A({loading:!1,error:null})}),[j]),isPersistent:M}};export{g as OAuthPopup,I as useOAuth2};
@@ -2,5 +2,5 @@
2
2
  type Props = {
3
3
  Component?: React.ReactElement;
4
4
  };
5
- declare const OAuthPopup: (props: Props) => JSX.Element;
6
- export default OAuthPopup;
5
+ export declare const OAuthPopup: ({ Component, }: Props) => import("react").ReactElement<any, string | import("react").JSXElementConstructor<any>>;
6
+ export {};
@@ -1,2 +1,3 @@
1
- export { default as OAuthPopup } from './OAuthPopup';
2
- export { default as useOAuth2, Oauth2Props } from './use-oauth2';
1
+ export * from './OAuthPopup';
2
+ export * from './use-oauth2';
3
+ export * from './types';
@@ -1,4 +1,16 @@
1
+ import { TMessageData, TOauth2Props } from './types';
1
2
  export declare const objectToQuery: (object: Record<string, string>) => string;
2
3
  export declare const queryToObject: (query: string) => {
3
4
  [k: string]: string;
4
5
  };
6
+ export declare const formatAuthorizeUrl: (authorizeUrl: string, clientId: string, redirectUri: string, scope: string, state: string, responseType: TOauth2Props['responseType'], extraQueryParameters?: TOauth2Props['extraQueryParameters']) => string;
7
+ export declare const generateState: () => string;
8
+ export declare const saveState: (state: string) => void;
9
+ export declare const removeState: () => void;
10
+ export declare const checkState: (receivedState: string) => boolean;
11
+ export declare const openPopup: (url: string) => Window | null;
12
+ export declare const closePopup: (popupRef: React.MutableRefObject<Window | null | undefined>) => void;
13
+ export declare const isWindowOpener: (opener: Window | null) => opener is Window;
14
+ export declare const openerPostMessage: (opener: Window, message: TMessageData) => void;
15
+ export declare const cleanup: (intervalRef: React.MutableRefObject<string | number | NodeJS.Timeout | undefined>, popupRef: React.MutableRefObject<Window | null | undefined>, handleMessageListener: any) => void;
16
+ export declare const formatExchangeCodeForTokenServerURL: (exchangeCodeForTokenServerURL: string, clientId: string, code: string, redirectUri: string, state: string) => string;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,33 @@
1
+ import { OAUTH_RESPONSE } from './constants';
2
+ export type TAuthTokenPayload = {
3
+ token_type: string;
4
+ expires_in: number;
5
+ access_token: string;
6
+ scope: string;
7
+ refresh_token: string;
8
+ };
9
+ export type TResponseTypeBasedProps<TData> = {
10
+ responseType: 'code';
11
+ exchangeCodeForTokenServerURL: string;
12
+ exchangeCodeForTokenMethod?: 'POST' | 'GET';
13
+ onSuccess?: (payload: TData) => void;
14
+ } | {
15
+ responseType: 'token';
16
+ onSuccess?: (payload: TData) => void;
17
+ };
18
+ export type TOauth2Props<TData = TAuthTokenPayload> = {
19
+ authorizeUrl: string;
20
+ clientId: string;
21
+ redirectUri: string;
22
+ scope?: string;
23
+ extraQueryParameters?: Record<string, any>;
24
+ onError?: (error: string) => void;
25
+ } & TResponseTypeBasedProps<TData>;
26
+ export type TState<TData = TAuthTokenPayload> = TData | null;
27
+ export type TMessageData = {
28
+ type: typeof OAUTH_RESPONSE;
29
+ error: string;
30
+ } | {
31
+ type: typeof OAUTH_RESPONSE;
32
+ payload: any;
33
+ };
@@ -0,0 +1,2 @@
1
+ import { TAuthTokenPayload, TOauth2Props } from './types';
2
+ export declare const useCheckProps: <TData = TAuthTokenPayload>(props: TOauth2Props<TData>) => void;
@@ -0,0 +1 @@
1
+ export {};
@@ -1,32 +1,9 @@
1
- export type AuthTokenPayload = {
2
- token_type: string;
3
- expires_in: number;
4
- access_token: string;
5
- scope: string;
6
- refresh_token: string;
7
- };
8
- export type ResponseTypeBasedProps<TData> = {
9
- responseType: 'code';
10
- exchangeCodeForTokenServerURL: string;
11
- exchangeCodeForTokenMethod?: 'POST' | 'GET';
12
- onSuccess?: (payload: TData) => void;
13
- } | {
14
- responseType: 'token';
15
- onSuccess?: (payload: TData) => void;
16
- };
17
- export type Oauth2Props<TData = AuthTokenPayload> = {
18
- authorizeUrl: string;
19
- clientId: string;
20
- redirectUri: string;
21
- scope?: string;
22
- extraQueryParameters?: Record<string, any>;
23
- onError?: (error: string) => void;
24
- } & ResponseTypeBasedProps<TData>;
25
- export type State<TData = AuthTokenPayload> = TData | null;
26
- declare const useOAuth2: <TData = AuthTokenPayload>(props: Oauth2Props<TData>) => {
27
- data: State<AuthTokenPayload>;
1
+ import { TAuthTokenPayload, TOauth2Props, TState } from './types';
2
+ export declare const useOAuth2: <TData = TAuthTokenPayload>(props: TOauth2Props<TData>) => {
3
+ data: TState;
28
4
  loading: boolean;
29
- error: null;
5
+ error: string | null;
30
6
  getAuth: () => () => void;
7
+ logout: () => void;
8
+ isPersistent: boolean;
31
9
  };
32
- export default useOAuth2;
@@ -0,0 +1 @@
1
+ export {};
package/dist/index.d.ts CHANGED
@@ -1,17 +1,21 @@
1
1
  /// <reference types="react" />
2
+ import * as react from 'react';
3
+
2
4
  type Props = {
3
5
  Component?: React.ReactElement;
4
6
  };
5
- declare const OAuthPopup: (props: Props) => JSX.Element;
7
+ declare const OAuthPopup: ({ Component, }: Props) => react.ReactElement<any, string | react.JSXElementConstructor<any>>;
8
+
9
+ declare const OAUTH_RESPONSE = "react-use-oauth2-response";
6
10
 
7
- type AuthTokenPayload = {
11
+ type TAuthTokenPayload = {
8
12
  token_type: string;
9
13
  expires_in: number;
10
14
  access_token: string;
11
15
  scope: string;
12
16
  refresh_token: string;
13
17
  };
14
- type ResponseTypeBasedProps<TData> = {
18
+ type TResponseTypeBasedProps<TData> = {
15
19
  responseType: 'code';
16
20
  exchangeCodeForTokenServerURL: string;
17
21
  exchangeCodeForTokenMethod?: 'POST' | 'GET';
@@ -20,20 +24,30 @@ type ResponseTypeBasedProps<TData> = {
20
24
  responseType: 'token';
21
25
  onSuccess?: (payload: TData) => void;
22
26
  };
23
- type Oauth2Props<TData = AuthTokenPayload> = {
27
+ type TOauth2Props<TData = TAuthTokenPayload> = {
24
28
  authorizeUrl: string;
25
29
  clientId: string;
26
30
  redirectUri: string;
27
31
  scope?: string;
28
32
  extraQueryParameters?: Record<string, any>;
29
33
  onError?: (error: string) => void;
30
- } & ResponseTypeBasedProps<TData>;
31
- type State<TData = AuthTokenPayload> = TData | null;
32
- declare const useOAuth2: <TData = AuthTokenPayload>(props: Oauth2Props<TData>) => {
33
- data: State<AuthTokenPayload>;
34
+ } & TResponseTypeBasedProps<TData>;
35
+ type TState<TData = TAuthTokenPayload> = TData | null;
36
+ type TMessageData = {
37
+ type: typeof OAUTH_RESPONSE;
38
+ error: string;
39
+ } | {
40
+ type: typeof OAUTH_RESPONSE;
41
+ payload: any;
42
+ };
43
+
44
+ declare const useOAuth2: <TData = TAuthTokenPayload>(props: TOauth2Props<TData>) => {
45
+ data: TState;
34
46
  loading: boolean;
35
- error: null;
47
+ error: string | null;
36
48
  getAuth: () => () => void;
49
+ logout: () => void;
50
+ isPersistent: boolean;
37
51
  };
38
52
 
39
- export { OAuthPopup, Oauth2Props, useOAuth2 };
53
+ export { OAuthPopup, TAuthTokenPayload, TMessageData, TOauth2Props, TResponseTypeBasedProps, TState, useOAuth2 };
package/package.json CHANGED
@@ -12,7 +12,7 @@
12
12
  "nodejs",
13
13
  "oauth2"
14
14
  ],
15
- "version": "1.1.0",
15
+ "version": "1.2.0",
16
16
  "description": "A React hook that handles OAuth2 authorization flow.",
17
17
  "license": "MIT",
18
18
  "homepage": "https://github.com/tasoskakour/react-use-oauth2#readme",
@@ -28,9 +28,10 @@
28
28
  "scripts": {
29
29
  "build": "rollup -c",
30
30
  "example": "rollup -c rollup.config.example.mjs -w --silent",
31
- "test": "NODE_ENV=test npm run lint && start-server-and-test example \"http://localhost:3000|http://localhost:3001\" run-test",
32
- "run-test": "jest --runInBand --detectOpenHandles --forceExit",
33
31
  "lint": "eslint . --cache",
32
+ "test-unit": "jest --detectOpenHandles --runInBand --config jest.config.unit.ts",
33
+ "test-e2e": "start-server-and-test example \"http://localhost:3000|http://localhost:3001\" \"jest --detectOpenHandles --runInBand --config jest.config.e2e.ts\"",
34
+ "test": "npm run lint && npm run test-unit && npm run test-e2e",
34
35
  "prepare": "husky install"
35
36
  },
36
37
  "browserslist": {
@@ -63,6 +64,7 @@
63
64
  "@rollup/plugin-run": "^3.0.1",
64
65
  "@rollup/plugin-terser": "^0.4.0",
65
66
  "@rollup/plugin-typescript": "^11.1.0",
67
+ "@testing-library/react": "^14.0.0",
66
68
  "@types/jest": "^29.5.0",
67
69
  "@types/node": "^18.15.11",
68
70
  "@types/react": "^18.0.33",
@@ -76,6 +78,8 @@
76
78
  "fastify": "^4.15.0",
77
79
  "husky": "^8.0.3",
78
80
  "jest": "^29.5.0",
81
+ "jest-environment-jsdom": "^29.5.0",
82
+ "jest-fetch-mock": "^3.0.3",
79
83
  "jest-puppeteer": "^8.0.6",
80
84
  "lint-staged": "^13.2.0",
81
85
  "puppeteer": "^19.8.3",
@@ -89,6 +93,7 @@
89
93
  "rollup-plugin-serve": "^2.0.2",
90
94
  "start-server-and-test": "^2.0.0",
91
95
  "ts-jest": "^29.1.0",
96
+ "ts-node": "^10.9.1",
92
97
  "typescript": "^5.0.3"
93
98
  },
94
99
  "engines": {