react-oauth2-code-pkce
Advanced tools
Comparing version 1.3.0-beta.0 to 1.3.0
import React from 'react'; | ||
import { IAuthContext, IAuthProvider } from "./Types"; | ||
import { IAuthContext, IAuthProvider } from './Types'; | ||
export declare const AuthContext: React.Context<IAuthContext>; | ||
export declare const AuthProvider: ({ authConfig, children }: IAuthProvider) => JSX.Element; |
"use strict"; | ||
var __assign = (this && this.__assign) || function () { | ||
__assign = Object.assign || function(t) { | ||
for (var s, i = 1, n = arguments.length; i < n; i++) { | ||
s = arguments[i]; | ||
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) | ||
t[p] = s[p]; | ||
} | ||
return t; | ||
}; | ||
return __assign.apply(this, arguments); | ||
}; | ||
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { | ||
@@ -41,68 +30,95 @@ if (k2 === undefined) k2 = k; | ||
exports.AuthProvider = exports.AuthContext = void 0; | ||
var react_1 = __importStar(require("react")); | ||
var authentication_1 = require("./authentication"); | ||
var Hooks_1 = __importDefault(require("./Hooks")); | ||
var validateAuthConfig_1 = require("./validateAuthConfig"); | ||
exports.AuthContext = (0, react_1.createContext)({ token: '', logOut: function () { return null; }, error: null }); | ||
var AuthProvider = function (_a) { | ||
var authConfig = _a.authConfig, children = _a.children; | ||
var _b = (0, Hooks_1.default)('ROCP_refreshToken', null), refreshToken = _b[0], setRefreshToken = _b[1]; | ||
var _c = (0, Hooks_1.default)('ROCP_token', null), token = _c[0], setToken = _c[1]; | ||
var _d = (0, Hooks_1.default)('ROCP_tokenExpire', null), tokenExpire = _d[0], setTokenExpire = _d[1]; | ||
var _e = (0, Hooks_1.default)('ROCP_idToken', null), idToken = _e[0], setIdToken = _e[1]; | ||
var _f = (0, Hooks_1.default)('ROCP_loginInProgress', false), loginInProgress = _f[0], setLoginInProgress = _f[1]; | ||
var _g = (0, react_1.useState)(null), tokenData = _g[0], setTokenData = _g[1]; | ||
var _h = (0, react_1.useState)(null), error = _h[0], setError = _h[1]; | ||
var interval; | ||
const react_1 = __importStar(require("react")); // eslint-disable-line | ||
const authentication_1 = require("./authentication"); | ||
const Hooks_1 = __importDefault(require("./Hooks")); | ||
const validateAuthConfig_1 = require("./validateAuthConfig"); | ||
const FALLBACK_EXPIRE_TIME = 600; // 10minutes | ||
exports.AuthContext = (0, react_1.createContext)({ | ||
token: '', | ||
logOut: () => null, | ||
error: null, | ||
}); | ||
const AuthProvider = ({ authConfig, children }) => { | ||
const [refreshToken, setRefreshToken] = (0, Hooks_1.default)('ROCP_refreshToken', undefined); | ||
const [refreshTokenExpire, setRefreshTokenExpire] = (0, Hooks_1.default)('ROCP_refreshTokenExpire', (0, authentication_1.epochAtSecondsFromNow)(2 * FALLBACK_EXPIRE_TIME)); | ||
const [token, setToken] = (0, Hooks_1.default)('ROCP_token', ''); | ||
const [tokenExpire, setTokenExpire] = (0, Hooks_1.default)('ROCP_tokenExpire', (0, authentication_1.epochAtSecondsFromNow)(FALLBACK_EXPIRE_TIME)); | ||
const [idToken, setIdToken] = (0, Hooks_1.default)('ROCP_idToken', undefined); | ||
const [loginInProgress, setLoginInProgress] = (0, Hooks_1.default)('ROCP_loginInProgress', false); | ||
const [tokenData, setTokenData] = (0, react_1.useState)(); | ||
const [error, setError] = (0, react_1.useState)(null); | ||
let interval; | ||
// Set default values and override from passed config | ||
var _j = authConfig.decodeToken, decodeToken = _j === void 0 ? true : _j, _k = authConfig.scope, scope = _k === void 0 ? "" : _k, _l = authConfig.preLogin, preLogin = _l === void 0 ? function () { return null; } : _l, _m = authConfig.postLogin, postLogin = _m === void 0 ? function () { return null; } : _m; | ||
var config = __assign({ decodeToken: decodeToken, scope: scope, preLogin: preLogin, postLogin: postLogin }, authConfig); | ||
const { decodeToken = true, scope = '', preLogin = () => null, postLogin = () => null } = authConfig; | ||
const config = { | ||
decodeToken: decodeToken, | ||
scope: scope, | ||
preLogin: preLogin, | ||
postLogin: postLogin, | ||
...authConfig, | ||
}; | ||
(0, validateAuthConfig_1.validateAuthConfig)(config); | ||
function logOut() { | ||
setRefreshToken(null); | ||
setToken(null); | ||
setIdToken(null); | ||
setTokenData(null); | ||
setRefreshToken(undefined); | ||
setToken(''); | ||
setTokenExpire((0, authentication_1.epochAtSecondsFromNow)(FALLBACK_EXPIRE_TIME)); | ||
setRefreshTokenExpire((0, authentication_1.epochAtSecondsFromNow)(FALLBACK_EXPIRE_TIME)); | ||
setIdToken(undefined); | ||
setTokenData(undefined); | ||
setLoginInProgress(false); | ||
} | ||
function handleTokenResponse(response) { | ||
setRefreshToken(response === null || response === void 0 ? void 0 : response.refresh_token); | ||
setToken(response.access_token); | ||
setTokenExpire((0, authentication_1.timeOfExpire)(response.expires_in)); | ||
setIdToken(response === null || response === void 0 ? void 0 : response.id_token); | ||
setRefreshToken(response.refresh_token); | ||
setTokenExpire((0, authentication_1.epochAtSecondsFromNow)(response.expires_in || FALLBACK_EXPIRE_TIME)); | ||
// If there is no refresh_token_expire, use access_token_expire + 10min. | ||
// If no access_token_expire, assume double the fallback expire time | ||
let refreshTokenExpire = response.refresh_token_expires_in || 2 * FALLBACK_EXPIRE_TIME; | ||
if (!response.refresh_token_expires_in && response.expires_in) { | ||
refreshTokenExpire = response.expires_in + FALLBACK_EXPIRE_TIME; | ||
} | ||
setRefreshTokenExpire((0, authentication_1.epochAtSecondsFromNow)(refreshTokenExpire)); | ||
setIdToken(response.id_token); | ||
setLoginInProgress(false); | ||
if (config.decodeToken) | ||
setTokenData((0, authentication_1.decodeJWT)(response.access_token)); | ||
try { | ||
if (config.decodeToken) | ||
setTokenData((0, authentication_1.decodeJWT)(response.access_token)); | ||
} | ||
catch (e) { | ||
setError(e.message); | ||
} | ||
} | ||
function refreshAccessToken() { | ||
if (refreshToken) { | ||
if ((0, authentication_1.tokenExpired)(tokenExpire)) { // The client has an expired token. Will try to get a new one with the refreshToken | ||
(0, authentication_1.fetchWithRefreshToken)({ config: config, refreshToken: refreshToken }) | ||
.then(function (result) { return handleTokenResponse(result); }) | ||
.catch(function (error) { | ||
if (token && (0, authentication_1.epochTimeIsPast)(tokenExpire)) { | ||
if (refreshToken && !(0, authentication_1.epochTimeIsPast)(refreshTokenExpire)) { | ||
(0, authentication_1.fetchWithRefreshToken)({ config, refreshToken }) | ||
.then((result) => handleTokenResponse(result)) | ||
.catch((error) => { | ||
setError(error); | ||
if ((0, authentication_1.errorMessageForExpiredRefreshToken)(error)) { | ||
logOut(); | ||
(0, authentication_1.login)(config); | ||
(0, authentication_1.logIn)(config); | ||
} | ||
}); | ||
} | ||
else { | ||
// The refresh token has expired. Need to log in from scratch. | ||
setLoginInProgress(true); | ||
(0, authentication_1.logIn)(config); | ||
} | ||
} | ||
else { // No refresh_token | ||
console.error("Tried to refresh token without a refresh token."); | ||
setError('Bad authorization state. Refreshing the page might solve the issue.'); | ||
} | ||
} | ||
// Register the 'check for soon expiring access token' interval (Every minute) | ||
(0, react_1.useEffect)(function () { | ||
interval = setInterval(function () { return refreshAccessToken(); }, 60000); | ||
return function () { return clearInterval(interval); }; | ||
(0, react_1.useEffect)(() => { | ||
interval = setInterval(() => refreshAccessToken(), 60000); // eslint-disable-line | ||
return () => clearInterval(interval); | ||
}, [token]); // This token dependency removes the old, and registers a new Interval when a new token is fetched. | ||
// Runs once on page load | ||
(0, react_1.useEffect)(function () { | ||
if (loginInProgress) { // The client has been redirected back from the Auth endpoint with an auth code | ||
var urlParams = new URLSearchParams(window.location.search); | ||
(0, react_1.useEffect)(() => { | ||
if (loginInProgress) { | ||
// The client has been redirected back from the Auth endpoint with an auth code | ||
const urlParams = new URLSearchParams(window.location.search); | ||
if (!urlParams.get('code')) { | ||
// This should not happen. There should be a 'code' parameter in the url by now..." | ||
var error_description = urlParams.get('error_description') || 'Bad authorization state. Refreshing the page might solve the issue.'; | ||
const error_description = urlParams.get('error_description') || 'Bad authorization state. Refreshing the page might solve the issue.'; | ||
console.error(error_description); | ||
@@ -112,11 +128,13 @@ setError(error_description); | ||
} | ||
else { // Request token from auth server with the auth code | ||
else { | ||
// Request token from auth server with the auth code | ||
(0, authentication_1.fetchTokens)(config) | ||
.then(function (tokens) { | ||
.then((tokens) => { | ||
handleTokenResponse(tokens); | ||
history.replaceState(null, "", location.pathname); // Clear ugly url params | ||
window.history.replaceState(null, '', window.location.pathname); // Clear ugly url params | ||
// Call any postLogin function in authConfig | ||
config.postLogin(); | ||
if (config?.postLogin) | ||
config.postLogin(); | ||
}) | ||
.catch(function (error) { | ||
.catch((error) => { | ||
setError(error); | ||
@@ -126,14 +144,21 @@ }); | ||
} | ||
else if (!token) { // First page visit | ||
else if (!token) { | ||
// First page visit | ||
setLoginInProgress(true); | ||
(0, authentication_1.login)(config); | ||
(0, authentication_1.logIn)(config); | ||
} | ||
else { | ||
if (decodeToken) | ||
setTokenData((0, authentication_1.decodeJWT)(token)); | ||
if (decodeToken) { | ||
try { | ||
setTokenData((0, authentication_1.decodeJWT)(token)); | ||
} | ||
catch (e) { | ||
setError(e.message); | ||
} | ||
} | ||
refreshAccessToken(); // Check if token should be updated | ||
} | ||
}, []); | ||
return (react_1.default.createElement(exports.AuthContext.Provider, { value: { tokenData: tokenData, token: token, idToken: idToken, logOut: logOut, error: error } }, children)); | ||
}, []); // eslint-disable-line | ||
return react_1.default.createElement(exports.AuthContext.Provider, { value: { tokenData, token, idToken, logOut, error } }, children); | ||
}; | ||
exports.AuthProvider = AuthProvider; |
@@ -1,14 +0,14 @@ | ||
import { TInternalConfig, TTokenData } from "./Types"; | ||
import { TInternalConfig, TTokenData, TTokenResponse } from './Types'; | ||
export declare const EXPIRED_REFRESH_TOKEN_ERROR_CODES: string[]; | ||
export declare function login(config: TInternalConfig): Promise<void>; | ||
export declare const fetchTokens: (config: TInternalConfig) => Promise<any>; | ||
export declare function logIn(config: TInternalConfig): Promise<void>; | ||
export declare const fetchTokens: (config: TInternalConfig) => Promise<TTokenResponse>; | ||
export declare const fetchWithRefreshToken: (props: { | ||
config: TInternalConfig; | ||
refreshToken: string; | ||
}) => Promise<any>; | ||
}) => Promise<TTokenResponse>; | ||
/** | ||
* Decodes the base64 encoded JWT. Returns a TToken. | ||
*/ | ||
export declare const decodeJWT: (token: string) => TTokenData | null; | ||
export declare const timeOfExpire: (validTimeDelta: number) => number; | ||
export declare const decodeJWT: (token: string) => TTokenData; | ||
export declare const epochAtSecondsFromNow: (secondsFromNow: number) => number; | ||
/** | ||
@@ -18,3 +18,3 @@ * Check if the Access Token has expired. | ||
*/ | ||
export declare function tokenExpired(tokenExpire: number): Boolean; | ||
export declare function epochTimeIsPast(timestamp: number): boolean; | ||
export declare const errorMessageForExpiredRefreshToken: (errorMessage: string) => boolean; |
"use strict"; | ||
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { | ||
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } | ||
return new (P || (P = Promise))(function (resolve, reject) { | ||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } | ||
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } | ||
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } | ||
step((generator = generator.apply(thisArg, _arguments || [])).next()); | ||
}); | ||
}; | ||
var __generator = (this && this.__generator) || function (thisArg, body) { | ||
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; | ||
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; | ||
function verb(n) { return function (v) { return step([n, v]); }; } | ||
function step(op) { | ||
if (f) throw new TypeError("Generator is already executing."); | ||
while (_) try { | ||
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; | ||
if (y = 0, t) op = [op[0] & 2, t.value]; | ||
switch (op[0]) { | ||
case 0: case 1: t = op; break; | ||
case 4: _.label++; return { value: op[1], done: false }; | ||
case 5: _.label++; y = op[1]; op = [0]; continue; | ||
case 7: op = _.ops.pop(); _.trys.pop(); continue; | ||
default: | ||
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } | ||
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } | ||
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } | ||
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } | ||
if (t[2]) _.ops.pop(); | ||
_.trys.pop(); continue; | ||
} | ||
op = body.call(thisArg, _); | ||
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } | ||
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; | ||
} | ||
}; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.errorMessageForExpiredRefreshToken = exports.tokenExpired = exports.timeOfExpire = exports.decodeJWT = exports.fetchWithRefreshToken = exports.fetchTokens = exports.login = exports.EXPIRED_REFRESH_TOKEN_ERROR_CODES = void 0; | ||
var pkceUtils_1 = require("./pkceUtils"); | ||
var codeVerifierStorageKey = "PKCE_code_verifier"; | ||
exports.errorMessageForExpiredRefreshToken = exports.epochTimeIsPast = exports.epochAtSecondsFromNow = exports.decodeJWT = exports.fetchWithRefreshToken = exports.fetchTokens = exports.logIn = exports.EXPIRED_REFRESH_TOKEN_ERROR_CODES = void 0; | ||
const pkceUtils_1 = require("./pkceUtils"); | ||
const codeVerifierStorageKey = 'PKCE_code_verifier'; | ||
// [ AzureAD,] | ||
exports.EXPIRED_REFRESH_TOKEN_ERROR_CODES = ["AADSTS700084"]; | ||
function login(config) { | ||
return __awaiter(this, void 0, void 0, function () { | ||
var codeVerifier; | ||
return __generator(this, function (_a) { | ||
codeVerifier = (0, pkceUtils_1.generateRandomString)(40); | ||
localStorage.setItem(codeVerifierStorageKey, codeVerifier); | ||
// Hash and Base64URL encode the code_verifier, used as the 'code_challenge' | ||
(0, pkceUtils_1.generateCodeChallenge)(codeVerifier).then(function (codeChallenge) { | ||
// Set query parameters and redirect user to OAuth2 authentication endpoint | ||
var params = new URLSearchParams({ | ||
response_type: 'code', | ||
client_id: config.clientId, | ||
scope: config.scope, | ||
redirect_uri: config.redirectUri, | ||
code_challenge: codeChallenge, | ||
code_challenge_method: 'S256', | ||
}); | ||
// Call any preLogin function in authConfig | ||
config.preLogin(); | ||
location.replace("".concat(config.authorizationEndpoint, "?").concat(params.toString())); | ||
}); | ||
return [2 /*return*/]; | ||
exports.EXPIRED_REFRESH_TOKEN_ERROR_CODES = ['AADSTS700084']; | ||
async function logIn(config) { | ||
// Create and store a random string in localStorage, used as the 'code_verifier' | ||
const codeVerifier = (0, pkceUtils_1.generateRandomString)(40); | ||
localStorage.setItem(codeVerifierStorageKey, codeVerifier); | ||
// Hash and Base64URL encode the code_verifier, used as the 'code_challenge' | ||
(0, pkceUtils_1.generateCodeChallenge)(codeVerifier).then((codeChallenge) => { | ||
// Set query parameters and redirect user to OAuth2 authentication endpoint | ||
const params = new URLSearchParams({ | ||
response_type: 'code', | ||
client_id: config.clientId, | ||
scope: config.scope, | ||
redirect_uri: config.redirectUri, | ||
code_challenge: codeChallenge, | ||
code_challenge_method: 'S256', | ||
}); | ||
// Call any preLogin function in authConfig | ||
if (config?.preLogin) | ||
config.preLogin(); | ||
window.location.replace(`${config.authorizationEndpoint}?${params.toString()}`); | ||
}); | ||
} | ||
exports.login = login; | ||
exports.logIn = logIn; | ||
// This is called a "type predicate". Which allow use to know which kind of response we got, in a type safe way. | ||
function isTokenResponse(body) { | ||
return body.access_token !== undefined; | ||
} | ||
function postWithFormData(tokenEndpoint, formData) { | ||
@@ -74,17 +38,19 @@ return fetch(tokenEndpoint, { | ||
body: formData, | ||
}) | ||
.then(function (response) { return response.json() | ||
.then(function (body) { | ||
}).then((response) => { | ||
if (!response.ok) { | ||
console.error(body.error_description); | ||
throw body.error_description; | ||
console.error(response); | ||
throw Error(response.statusText); | ||
} | ||
return body; | ||
}); }) | ||
.catch(function (error) { | ||
console.error(error); | ||
throw (error === null || error === void 0 ? void 0 : error.message) || error; | ||
return response.json().then((body) => { | ||
if (isTokenResponse(body)) { | ||
return body; | ||
} | ||
else { | ||
console.error(body); | ||
throw Error(body.error_description); | ||
} | ||
}); | ||
}); | ||
} | ||
var fetchTokens = function (config) { | ||
const fetchTokens = (config) => { | ||
/* | ||
@@ -95,12 +61,12 @@ The browser has been redirected from the authentication endpoint with | ||
*/ | ||
var urlParams = new URLSearchParams(window.location.search); | ||
var authCode = urlParams.get('code'); | ||
var codeVerifier = window.localStorage.getItem(codeVerifierStorageKey); | ||
const urlParams = new URLSearchParams(window.location.search); | ||
const authCode = urlParams.get('code'); | ||
const codeVerifier = window.localStorage.getItem(codeVerifierStorageKey); | ||
if (!authCode) { | ||
throw "Parameter 'code' not found in URL. \nHas authentication taken place?"; | ||
throw Error("Parameter 'code' not found in URL. \nHas authentication taken place?"); | ||
} | ||
if (!codeVerifier) { | ||
throw "Can't get tokens without the CodeVerifier. \nHas authentication taken place?"; | ||
throw Error("Can't get tokens without the CodeVerifier. \nHas authentication taken place?"); | ||
} | ||
var formData = new FormData(); | ||
const formData = new FormData(); | ||
formData.append('grant_type', 'authorization_code'); | ||
@@ -115,5 +81,5 @@ formData.append('code', authCode); | ||
exports.fetchTokens = fetchTokens; | ||
var fetchWithRefreshToken = function (props) { | ||
var config = props.config, refreshToken = props.refreshToken; | ||
var formData = new FormData(); | ||
const fetchWithRefreshToken = (props) => { | ||
const { config, refreshToken } = props; | ||
const formData = new FormData(); | ||
formData.append('grant_type', 'refresh_token'); | ||
@@ -130,7 +96,7 @@ formData.append('refresh_token', refreshToken); | ||
*/ | ||
var decodeJWT = function (token) { | ||
const decodeJWT = (token) => { | ||
try { | ||
var base64Url = token.split('.')[1]; | ||
var base64 = base64Url.replace(/-/g, '+').replace(/_/g, '/'); | ||
var jsonPayload = decodeURIComponent(atob(base64) | ||
const base64Url = token.split('.')[1]; | ||
const base64 = base64Url.replace(/-/g, '+').replace(/_/g, '/'); | ||
const jsonPayload = decodeURIComponent(atob(base64) | ||
.split('') | ||
@@ -145,5 +111,4 @@ .map(function (c) { | ||
console.error(e); | ||
console.error("Failed to decode the access token.\n\tIs it a proper Java Web Token?\n\t" + | ||
throw Error('Failed to decode the access token.\n\tIs it a proper Java Web Token?\n\t' + | ||
"You can disable JWT decoding by setting the 'decodeToken' value to 'false' the configuration."); | ||
return null; | ||
} | ||
@@ -153,4 +118,4 @@ }; | ||
// Returns epoch time (in seconds) for when the token will expire | ||
var timeOfExpire = function (validTimeDelta) { return Math.round(Date.now() / 1000 + validTimeDelta); }; | ||
exports.timeOfExpire = timeOfExpire; | ||
const epochAtSecondsFromNow = (secondsFromNow) => Math.round(Date.now() / 1000 + secondsFromNow); | ||
exports.epochAtSecondsFromNow = epochAtSecondsFromNow; | ||
/** | ||
@@ -160,12 +125,11 @@ * Check if the Access Token has expired. | ||
*/ | ||
function tokenExpired(tokenExpire) { | ||
var now = Math.round(Date.now()) / 1000; | ||
var bufferTimeInSeconds = 5 * 60; // minutes * seconds | ||
var nowWithBuffer = now + bufferTimeInSeconds; | ||
return nowWithBuffer >= tokenExpire; | ||
function epochTimeIsPast(timestamp) { | ||
const now = Math.round(Date.now()) / 1000; | ||
const nowWithBuffer = now + 120; | ||
return nowWithBuffer >= timestamp; | ||
} | ||
exports.tokenExpired = tokenExpired; | ||
var errorMessageForExpiredRefreshToken = function (errorMessage) { | ||
var expired = false; | ||
exports.EXPIRED_REFRESH_TOKEN_ERROR_CODES.forEach(function (errorCode) { | ||
exports.epochTimeIsPast = epochTimeIsPast; | ||
const errorMessageForExpiredRefreshToken = (errorMessage) => { | ||
let expired = false; | ||
exports.EXPIRED_REFRESH_TOKEN_ERROR_CODES.forEach((errorCode) => { | ||
if (errorMessage.includes(errorCode)) { | ||
@@ -172,0 +136,0 @@ expired = true; |
@@ -1,2 +0,2 @@ | ||
declare function useLocalStorage<T>(key: string, initialValue: T): [any, Function]; | ||
declare function useLocalStorage<T>(key: string, initialValue: T): [T, (v: T) => void]; | ||
export default useLocalStorage; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
var react_1 = require("react"); | ||
const react_1 = require("react"); | ||
function useLocalStorage(key, initialValue) { | ||
var _a = (0, react_1.useState)(function () { | ||
const [storedValue, setStoredValue] = (0, react_1.useState)(() => { | ||
const item = localStorage.getItem(key); | ||
try { | ||
var item = localStorage.getItem(key); | ||
return item ? JSON.parse(item) : initialValue; | ||
@@ -13,6 +13,6 @@ } | ||
} | ||
}), storedValue = _a[0], setStoredValue = _a[1]; | ||
var setValue = function (value) { | ||
}); | ||
const setValue = (value) => { | ||
try { | ||
var valueToStore = value instanceof Function ? value(storedValue) : value; | ||
const valueToStore = value instanceof Function ? value(storedValue) : value; | ||
setStoredValue(valueToStore); | ||
@@ -22,3 +22,3 @@ localStorage.setItem(key, JSON.stringify(valueToStore)); | ||
catch (error) { | ||
console.log(error); | ||
console.log(`Failed to store value '${value}' for key '${key}'`); | ||
} | ||
@@ -25,0 +25,0 @@ }; |
@@ -1,2 +0,2 @@ | ||
export { AuthProvider, AuthContext } from "./AuthContext"; | ||
export type { TAuthConfig } from "./Types"; | ||
export { AuthProvider, AuthContext } from './AuthContext'; | ||
export type { TAuthConfig, IAuthProvider, IAuthContext } from './Types'; |
export declare function getRandomInteger(range: number): number; | ||
export declare function generateRandomString(length: number): string; | ||
/** | ||
* PKCE Code Challenge = base64url(hash(codeVerifier)) | ||
* PKCE Code Challenge = base64url(hash(codeVerifier)) | ||
*/ | ||
export declare function generateCodeChallenge(codeVerifier: string): Promise<string>; |
"use strict"; | ||
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { | ||
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } | ||
return new (P || (P = Promise))(function (resolve, reject) { | ||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } | ||
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } | ||
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } | ||
step((generator = generator.apply(thisArg, _arguments || [])).next()); | ||
}); | ||
}; | ||
var __generator = (this && this.__generator) || function (thisArg, body) { | ||
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; | ||
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; | ||
function verb(n) { return function (v) { return step([n, v]); }; } | ||
function step(op) { | ||
if (f) throw new TypeError("Generator is already executing."); | ||
while (_) try { | ||
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; | ||
if (y = 0, t) op = [op[0] & 2, t.value]; | ||
switch (op[0]) { | ||
case 0: case 1: t = op; break; | ||
case 4: _.label++; return { value: op[1], done: false }; | ||
case 5: _.label++; y = op[1]; op = [0]; continue; | ||
case 7: op = _.ops.pop(); _.trys.pop(); continue; | ||
default: | ||
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } | ||
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } | ||
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } | ||
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } | ||
if (t[2]) _.ops.pop(); | ||
_.trys.pop(); continue; | ||
} | ||
op = body.call(thisArg, _); | ||
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } | ||
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; | ||
} | ||
}; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.generateCodeChallenge = exports.generateRandomString = exports.getRandomInteger = void 0; | ||
function getRandomInteger(range) { | ||
var max_range = 256; // Highest possible number in Uint8 | ||
const max_range = 256; // Highest possible number in Uint8 | ||
// Create byte array and fill with 1 random number | ||
var byteArray = new Uint8Array(1); | ||
const byteArray = new Uint8Array(1); | ||
window.crypto.getRandomValues(byteArray); // This is the new, and safer API than Math.Random() | ||
@@ -52,5 +16,5 @@ // If the generated number is out of range, try again | ||
function generateRandomString(length) { | ||
var text = ''; | ||
var possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; | ||
for (var i = 0; i < length; i++) { | ||
let text = ''; | ||
const possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; | ||
for (let i = 0; i < length; i++) { | ||
text += possible.charAt(getRandomInteger(possible.length - 1)); | ||
@@ -62,31 +26,15 @@ } | ||
/** | ||
* PKCE Code Challenge = base64url(hash(codeVerifier)) | ||
* PKCE Code Challenge = base64url(hash(codeVerifier)) | ||
*/ | ||
function generateCodeChallenge(codeVerifier) { | ||
return __awaiter(this, void 0, void 0, function () { | ||
var encoder, bytes, hash, hashString, base64, base64url; | ||
return __generator(this, function (_a) { | ||
switch (_a.label) { | ||
case 0: | ||
encoder = new TextEncoder(); | ||
bytes = encoder.encode(codeVerifier) // Encode the verifier to a byteArray | ||
; | ||
return [4 /*yield*/, window.crypto.subtle.digest('SHA-256', bytes) | ||
// @ts-ignore | ||
]; // sha256 hash it | ||
case 1: | ||
hash = _a.sent() // sha256 hash it | ||
; | ||
hashString = String.fromCharCode.apply(String, new Uint8Array(hash)); | ||
base64 = btoa(hashString) // Base64 encode the verifier hash | ||
; | ||
base64url = base64 // Base64Url encode the base64 encoded string, making it safe as a query param | ||
.replace(/=/g, '') | ||
.replace(/\+/g, '-') | ||
.replace(/\//g, '_'); | ||
return [2 /*return*/, base64url]; | ||
} | ||
}); | ||
}); | ||
async function generateCodeChallenge(codeVerifier) { | ||
const encoder = new TextEncoder(); | ||
const bytes = encoder.encode(codeVerifier); // Encode the verifier to a byteArray | ||
const hash = await window.crypto.subtle.digest('SHA-256', bytes); // sha256 hash it | ||
const hashString = String.fromCharCode(...new Uint8Array(hash)); | ||
const base64 = btoa(hashString); // Base64 encode the verifier hash | ||
return base64 // Base64Url encode the base64 encoded string, making it safe as a query param | ||
.replace(/=/g, '') | ||
.replace(/\+/g, '-') | ||
.replace(/\//g, '_'); | ||
} | ||
exports.generateCodeChallenge = generateCodeChallenge; |
@@ -1,12 +0,13 @@ | ||
import { ReactNode } from "react"; | ||
import { ReactNode } from 'react'; | ||
export declare type TTokenData = { | ||
exp: number; | ||
[x: string]: any; | ||
[x: string]: unknown; | ||
}; | ||
export declare type TTokenResponse = { | ||
access_token: string; | ||
expires_in: number; | ||
scope: string; | ||
token_type: string; | ||
expires_in?: number; | ||
refresh_token?: string; | ||
refresh_token_expires_in?: number; | ||
id_token?: string; | ||
@@ -21,4 +22,4 @@ }; | ||
logOut: () => void; | ||
error: any; | ||
tokenData?: TTokenData | null; | ||
error: string | null; | ||
tokenData?: TTokenData; | ||
idToken?: string; | ||
@@ -34,6 +35,10 @@ } | ||
logoutRedirect?: string; | ||
preLogin?: Function; | ||
postLogin?: Function; | ||
preLogin?: () => void; | ||
postLogin?: () => void; | ||
decodeToken?: boolean; | ||
}; | ||
export declare type TAzureADErrorResponse = { | ||
error_description: string; | ||
[k: string]: unknown; | ||
}; | ||
export declare type TInternalConfig = { | ||
@@ -45,5 +50,5 @@ clientId: string; | ||
scope: string; | ||
preLogin: Function; | ||
postLogin: Function; | ||
preLogin?: () => void; | ||
postLogin?: () => void; | ||
decodeToken: boolean; | ||
}; |
@@ -1,2 +0,2 @@ | ||
import { TAuthConfig } from "./Types"; | ||
export declare function validateAuthConfig(authConfig: TAuthConfig): void; | ||
import { TInternalConfig } from './Types'; | ||
export declare function validateAuthConfig(config: TInternalConfig): void; |
@@ -5,15 +5,15 @@ "use strict"; | ||
function stringIsUnset(value) { | ||
var unset = ["", undefined, null]; | ||
const unset = ['', undefined, null]; | ||
return unset.includes(value); | ||
} | ||
function validateAuthConfig(authConfig) { | ||
if (stringIsUnset(authConfig === null || authConfig === void 0 ? void 0 : authConfig.clientId)) | ||
throw "'clientId' must be set in the 'AuthConfig' object passed to 'react-oauth2-code-pkce' AuthProvider"; | ||
if (stringIsUnset(authConfig === null || authConfig === void 0 ? void 0 : authConfig.authorizationEndpoint)) | ||
throw "'authorizationEndpoint' must be set in the 'AuthConfig' object passed to 'react-oauth2-code-pkce' AuthProvider"; | ||
if (stringIsUnset(authConfig === null || authConfig === void 0 ? void 0 : authConfig.tokenEndpoint)) | ||
throw "'tokenEndpoint' must be set in the 'AuthConfig' object passed to 'react-oauth2-code-pkce' AuthProvider"; | ||
if (stringIsUnset(authConfig === null || authConfig === void 0 ? void 0 : authConfig.redirectUri)) | ||
throw "'redirectUri' must be set in the 'AuthConfig' object passed to 'react-oauth2-code-pkce' AuthProvider"; | ||
function validateAuthConfig(config) { | ||
if (stringIsUnset(config?.clientId)) | ||
throw Error("'clientId' must be set in the 'AuthConfig' object passed to 'react-oauth2-code-pkce' AuthProvider"); | ||
if (stringIsUnset(config?.authorizationEndpoint)) | ||
throw Error("'authorizationEndpoint' must be set in the 'AuthConfig' object passed to 'react-oauth2-code-pkce' AuthProvider"); | ||
if (stringIsUnset(config?.tokenEndpoint)) | ||
throw Error("'tokenEndpoint' must be set in the 'AuthConfig' object passed to 'react-oauth2-code-pkce' AuthProvider"); | ||
if (stringIsUnset(config?.redirectUri)) | ||
throw Error("'redirectUri' must be set in the 'AuthConfig' object passed to 'react-oauth2-code-pkce' AuthProvider"); | ||
} | ||
exports.validateAuthConfig = validateAuthConfig; |
{ | ||
"name": "react-oauth2-code-pkce", | ||
"version": "1.3.0-beta.0", | ||
"version": "1.3.0", | ||
"description": "Plug-and-play react package for OAuth2 Authorization Code flow with PKCE", | ||
@@ -13,3 +13,3 @@ "main": "dist/index.js", | ||
"peerDependencies": { | ||
"react": "17.0.2" | ||
"react": "^17.0.2" | ||
}, | ||
@@ -16,0 +16,0 @@ "scripts": { |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
0
24295
471