react-oauth2-code-pkce
Advanced tools
Comparing version 1.7.0 to 1.7.1
@@ -34,2 +34,4 @@ "use strict"; | ||
const validateAuthConfig_1 = require("./validateAuthConfig"); | ||
const timeUtils_1 = require("./timeUtils"); | ||
const decodeJWT_1 = require("./decodeJWT"); | ||
const FALLBACK_EXPIRE_TIME = 600; // 10minutes | ||
@@ -45,5 +47,5 @@ exports.AuthContext = (0, react_1.createContext)({ | ||
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 [refreshTokenExpire, setRefreshTokenExpire] = (0, Hooks_1.default)('ROCP_refreshTokenExpire', (0, timeUtils_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 [tokenExpire, setTokenExpire] = (0, Hooks_1.default)('ROCP_tokenExpire', (0, timeUtils_1.epochAtSecondsFromNow)(FALLBACK_EXPIRE_TIME)); | ||
const [idToken, setIdToken] = (0, Hooks_1.default)('ROCP_idToken', undefined); | ||
@@ -68,7 +70,9 @@ const [loginInProgress, setLoginInProgress] = (0, Hooks_1.default)('ROCP_loginInProgress', false); | ||
setToken(''); | ||
setTokenExpire((0, authentication_1.epochAtSecondsFromNow)(FALLBACK_EXPIRE_TIME)); | ||
setRefreshTokenExpire((0, authentication_1.epochAtSecondsFromNow)(FALLBACK_EXPIRE_TIME)); | ||
setTokenExpire((0, timeUtils_1.epochAtSecondsFromNow)(FALLBACK_EXPIRE_TIME)); | ||
setRefreshTokenExpire((0, timeUtils_1.epochAtSecondsFromNow)(FALLBACK_EXPIRE_TIME)); | ||
setIdToken(undefined); | ||
setTokenData(undefined); | ||
setLoginInProgress(false); | ||
if (config?.logoutEndpoint && refreshToken) | ||
(0, authentication_1.redirectToLogout)(config, refreshToken); | ||
} | ||
@@ -82,3 +86,3 @@ function login() { | ||
setRefreshToken(response.refresh_token); | ||
setTokenExpire((0, authentication_1.epochAtSecondsFromNow)(response.expires_in || FALLBACK_EXPIRE_TIME)); | ||
setTokenExpire((0, timeUtils_1.epochAtSecondsFromNow)(response.expires_in || FALLBACK_EXPIRE_TIME)); | ||
// If there is no refresh_token_expire, use access_token_expire + 10min. | ||
@@ -90,3 +94,3 @@ // If no access_token_expire, assume double the fallback expire time | ||
} | ||
setRefreshTokenExpire((0, authentication_1.epochAtSecondsFromNow)(refreshTokenExpire)); | ||
setRefreshTokenExpire((0, timeUtils_1.epochAtSecondsFromNow)(refreshTokenExpire)); | ||
setIdToken(response.id_token); | ||
@@ -96,3 +100,3 @@ setLoginInProgress(false); | ||
if (config.decodeToken) | ||
setTokenData((0, authentication_1.decodeJWT)(response.access_token)); | ||
setTokenData((0, decodeJWT_1.decodeJWT)(response.access_token)); | ||
} | ||
@@ -104,4 +108,4 @@ catch (e) { | ||
function refreshAccessToken() { | ||
if (token && (0, authentication_1.epochTimeIsPast)(tokenExpire)) { | ||
if (refreshToken && !(0, authentication_1.epochTimeIsPast)(refreshTokenExpire)) { | ||
if (token && (0, timeUtils_1.epochTimeIsPast)(tokenExpire)) { | ||
if (refreshToken && !(0, timeUtils_1.epochTimeIsPast)(refreshTokenExpire)) { | ||
(0, authentication_1.fetchWithRefreshToken)({ config, refreshToken }) | ||
@@ -163,3 +167,3 @@ .then((result) => handleTokenResponse(result)) | ||
try { | ||
setTokenData((0, authentication_1.decodeJWT)(token)); | ||
setTokenData((0, decodeJWT_1.decodeJWT)(token)); | ||
} | ||
@@ -166,0 +170,0 @@ catch (e) { |
@@ -1,2 +0,2 @@ | ||
import { TInternalConfig, TTokenData, TTokenResponse } from './Types'; | ||
import { TInternalConfig, TTokenResponse } from './Types'; | ||
export declare const EXPIRED_REFRESH_TOKEN_ERROR_CODES: string[]; | ||
@@ -9,12 +9,3 @@ export declare function redirectToLogin(config: TInternalConfig): Promise<void>; | ||
}) => Promise<TTokenResponse>; | ||
/** | ||
* Decodes the base64 encoded JWT. Returns a TToken. | ||
*/ | ||
export declare const decodeJWT: (token: string) => TTokenData; | ||
export declare const epochAtSecondsFromNow: (secondsFromNow: number) => number; | ||
/** | ||
* Check if the Access Token has expired. | ||
* Will return True if the token has expired, OR there is less than 5min until it expires. | ||
*/ | ||
export declare function epochTimeIsPast(timestamp: number): boolean; | ||
export declare function redirectToLogout(config: TInternalConfig, token: string): void; | ||
export declare const errorMessageForExpiredRefreshToken: (errorMessage: string) => boolean; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.errorMessageForExpiredRefreshToken = exports.epochTimeIsPast = exports.epochAtSecondsFromNow = exports.decodeJWT = exports.fetchWithRefreshToken = exports.fetchTokens = exports.redirectToLogin = exports.EXPIRED_REFRESH_TOKEN_ERROR_CODES = void 0; | ||
exports.errorMessageForExpiredRefreshToken = exports.redirectToLogout = exports.fetchWithRefreshToken = exports.fetchTokens = exports.redirectToLogin = exports.EXPIRED_REFRESH_TOKEN_ERROR_CODES = void 0; | ||
const pkceUtils_1 = require("./pkceUtils"); | ||
const httpUtils_1 = require("./httpUtils"); | ||
const codeVerifierStorageKey = 'PKCE_code_verifier'; | ||
@@ -35,19 +36,4 @@ // [ AzureAD,] | ||
} | ||
function buildUrlEncodedRequest(tokenRequest) { | ||
let queryString = ''; | ||
for (const [key, value] of Object.entries(tokenRequest)) { | ||
queryString += (queryString ? '&' : '') + key + '=' + encodeURIComponent(value); | ||
} | ||
return queryString; | ||
} | ||
function postWithXForm(tokenEndpoint, tokenRequest) { | ||
return fetch(tokenEndpoint, { | ||
method: 'POST', | ||
body: buildUrlEncodedRequest(tokenRequest), | ||
headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, | ||
}).then((response) => { | ||
if (!response.ok) { | ||
console.error(response); | ||
throw Error(response.statusText); | ||
} | ||
function postTokenRequest(tokenEndpoint, tokenRequest) { | ||
return (0, httpUtils_1.postWithXForm)(tokenEndpoint, tokenRequest).then((response) => { | ||
return response.json().then((body) => { | ||
@@ -90,3 +76,3 @@ if (isTokenResponse(body)) { | ||
}; | ||
return postWithXForm(config.tokenEndpoint, tokenRequest); | ||
return postTokenRequest(config.tokenEndpoint, tokenRequest); | ||
}; | ||
@@ -96,3 +82,3 @@ exports.fetchTokens = fetchTokens; | ||
const { config, refreshToken } = props; | ||
const tokenRequest = { | ||
const refreshRequest = { | ||
grant_type: 'refresh_token', | ||
@@ -104,40 +90,17 @@ refresh_token: refreshToken, | ||
}; | ||
return postWithXForm(config.tokenEndpoint, tokenRequest); | ||
return postTokenRequest(config.tokenEndpoint, refreshRequest); | ||
}; | ||
exports.fetchWithRefreshToken = fetchWithRefreshToken; | ||
/** | ||
* Decodes the base64 encoded JWT. Returns a TToken. | ||
*/ | ||
const decodeJWT = (token) => { | ||
try { | ||
const base64Url = token.split('.')[1]; | ||
const base64 = base64Url.replace(/-/g, '+').replace(/_/g, '/'); | ||
const jsonPayload = decodeURIComponent(atob(base64) | ||
.split('') | ||
.map(function (c) { | ||
return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2); | ||
}) | ||
.join('')); | ||
return JSON.parse(jsonPayload); | ||
} | ||
catch (e) { | ||
console.error(e); | ||
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."); | ||
} | ||
}; | ||
exports.decodeJWT = decodeJWT; | ||
// Returns epoch time (in seconds) for when the token will expire | ||
const epochAtSecondsFromNow = (secondsFromNow) => Math.round(Date.now() / 1000 + secondsFromNow); | ||
exports.epochAtSecondsFromNow = epochAtSecondsFromNow; | ||
/** | ||
* Check if the Access Token has expired. | ||
* Will return True if the token has expired, OR there is less than 5min until it expires. | ||
*/ | ||
function epochTimeIsPast(timestamp) { | ||
const now = Math.round(Date.now()) / 1000; | ||
const nowWithBuffer = now + 120; | ||
return nowWithBuffer >= timestamp; | ||
function redirectToLogout(config, token) { | ||
const params = new URLSearchParams({ | ||
token: token, | ||
// TODO: Add config param for token type | ||
token_type_hint: 'refresh_token', | ||
client_id: config.clientId, | ||
// TODO: Add extra logout params | ||
post_logout_redirect_uri: config.redirectUri, | ||
}); | ||
window.location.replace(`${config.logoutEndpoint}?${params.toString()}`); | ||
} | ||
exports.epochTimeIsPast = epochTimeIsPast; | ||
exports.redirectToLogout = redirectToLogout; | ||
const errorMessageForExpiredRefreshToken = (errorMessage) => { | ||
@@ -144,0 +107,0 @@ let expired = false; |
@@ -73,2 +73,3 @@ import { ReactNode } from 'react'; | ||
scope: string; | ||
logoutEndpoint?: string; | ||
preLogin?: () => void; | ||
@@ -75,0 +76,0 @@ postLogin?: () => void; |
{ | ||
"name": "react-oauth2-code-pkce", | ||
"version": "1.7.0", | ||
"version": "1.7.1", | ||
"description": "Plug-and-play react package for OAuth2 Authorization Code flow with PKCE", | ||
@@ -5,0 +5,0 @@ "main": "dist/index.js", |
@@ -113,6 +113,9 @@ # react-oauth2-pkce · [![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/soofstad/react-oauth2-pkce/blob/main/LICENSE) [![npm version](https://img.shields.io/npm/v/react-oauth2-code-pkce)](https://www.npmjs.com/package/react-oauth2-code-pkce) ![CI](https://github.com/soofstad/react-oauth2-pkce/actions/workflows/tests.yaml/badge.svg) | ||
type TAuthConfig = { | ||
// For required parameters, refer to the auth providers documentation | ||
// Id of your app at the authentication provider | ||
clientId: string // Required | ||
// URL for the authentication endpoint at the authentication provider | ||
authorizationEndpoint: string // Required | ||
// URL for the token endpoint at the authentication provider | ||
tokenEndpoint: string // Required | ||
// Which URL the auth provider should redirect the user after loging out | ||
redirectUri: string // Required | ||
@@ -119,0 +122,0 @@ scope?: string // default: '' |
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
30265
22
570
158