react-oauth2-code-pkce
Advanced tools
Comparing version 1.7.1 to 1.8.0
@@ -55,3 +55,3 @@ "use strict"; | ||
// Set default values for internal config object | ||
const { autoLogin = true, decodeToken = true, scope = '', preLogin = () => null, postLogin = () => null, } = authConfig; | ||
const { autoLogin = true, decodeToken = true, scope = '', preLogin = () => null, postLogin = () => null, onRefreshTokenExpire = undefined, } = authConfig; | ||
const config = { | ||
@@ -64,5 +64,6 @@ ...authConfig, | ||
postLogin: postLogin, | ||
onRefreshTokenExpire: onRefreshTokenExpire, | ||
}; | ||
(0, validateAuthConfig_1.validateAuthConfig)(config); | ||
function logOut() { | ||
function clearStorage() { | ||
setRefreshToken(undefined); | ||
@@ -75,2 +76,5 @@ setToken(''); | ||
setLoginInProgress(false); | ||
} | ||
function logOut() { | ||
clearStorage(); | ||
if (config?.logoutEndpoint && refreshToken) | ||
@@ -104,3 +108,3 @@ (0, authentication_1.redirectToLogout)(config, refreshToken); | ||
} | ||
function refreshAccessToken() { | ||
function refreshAccessToken(initial = false) { | ||
if (token && (0, timeUtils_1.epochTimeIsPast)(tokenExpire)) { | ||
@@ -119,4 +123,8 @@ if (refreshToken && !(0, timeUtils_1.epochTimeIsPast)(refreshTokenExpire)) { | ||
else { | ||
// The refresh token has expired. Need to log in from scratch. | ||
login(); | ||
if (initial) | ||
return login(); | ||
if (onRefreshTokenExpire) | ||
onRefreshTokenExpire({ login }); | ||
else | ||
login(); // TODO Breaking change - remove automatic login during ongoing session | ||
} | ||
@@ -171,3 +179,3 @@ } | ||
} | ||
refreshAccessToken(); // Check if token should be updated | ||
refreshAccessToken(true); // Check if token should be updated | ||
} | ||
@@ -174,0 +182,0 @@ }, []); // eslint-disable-line |
@@ -24,4 +24,13 @@ "use strict"; | ||
}; | ||
(0, react_1.useEffect)(() => { | ||
const storageEventHandler = (event) => { | ||
if (event.storageArea === localStorage && event.key === key) { | ||
setStoredValue(JSON.parse(event.newValue ?? '')); | ||
} | ||
}; | ||
window.addEventListener('storage', storageEventHandler, false); | ||
return () => window.removeEventListener('storage', storageEventHandler, false); | ||
}); | ||
return [storedValue, setValue]; | ||
} | ||
exports.default = useLocalStorage; |
@@ -51,2 +51,3 @@ import { ReactNode } from 'react'; | ||
postLogin?: () => void; | ||
onRefreshTokenExpire?: (event: TRefreshTokenExpiredEvent) => void; | ||
decodeToken?: boolean; | ||
@@ -64,2 +65,5 @@ autoLogin?: boolean; | ||
}; | ||
export declare type TRefreshTokenExpiredEvent = { | ||
login: () => void; | ||
}; | ||
export declare type TAzureADErrorResponse = { | ||
@@ -78,2 +82,3 @@ error_description: string; | ||
postLogin?: () => void; | ||
onRefreshTokenExpire?: (event: TRefreshTokenExpiredEvent) => void; | ||
decodeToken: boolean; | ||
@@ -80,0 +85,0 @@ autoLogin: boolean; |
{ | ||
"name": "react-oauth2-code-pkce", | ||
"version": "1.7.1", | ||
"version": "1.8.0", | ||
"description": "Plug-and-play react package for OAuth2 Authorization Code flow with PKCE", | ||
@@ -5,0 +5,0 @@ "main": "dist/index.js", |
100
README.md
@@ -1,8 +0,8 @@ | ||
# 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) | ||
# react-oauth2-code-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) | ||
Plug-and-play react package for OAuth2 Authorization Code flow with PKCE | ||
React package for OAuth2 Authorization Code flow with PKCE | ||
Adhering to the RFCs recommendations, cryptographically sound, and with __zero__ dependencies! | ||
## What is OAuth2 Authorization Code flow with Proof Key for Code Exchange (PKCE)? | ||
## What is OAuth2 Authorization Code Flow with Proof Key for Code Exchange? | ||
@@ -21,2 +21,3 @@ Short version; | ||
- Pre- and Post-login callbacks | ||
- Session expired callback | ||
- Silently refreshes short-lived access tokens in the background | ||
@@ -28,5 +29,3 @@ - Decodes JWT's | ||
```javascript | ||
import React, { useContext } from 'react' | ||
import ReactDOM from 'react-dom' | ||
```tsx | ||
import { AuthContext, AuthProvider, TAuthConfig } from "react-oauth2-code-pkce" | ||
@@ -42,57 +41,22 @@ | ||
function LoginInfo() { | ||
const { | ||
tokenData, | ||
token, | ||
login, | ||
logOut, | ||
error, | ||
loginInProgress | ||
} = useContext(AuthContext) | ||
// Stops the webpage from flickering while logging in | ||
if (loginInProgress) return null | ||
if (error) { | ||
return ( | ||
<> | ||
<div style={{ color: 'red' }}> | ||
An error occurred during authentication: {error} | ||
</div> | ||
<button onClick={() => logOut()}>Logout</button> | ||
</> | ||
) | ||
} | ||
if (!token) | ||
return ( | ||
<> | ||
<div style={{ backgroundColor: 'red' }}> | ||
You are not logged in | ||
</div> | ||
<button onClick={() => login()}>Login</button> | ||
</> | ||
) | ||
return ( | ||
<> | ||
<div> | ||
<h4>Access Token (JWT)</h4> | ||
const UserInfo = (): JSX.Element => { | ||
const {token, tokenData} = useContext<IAuthContext>(AuthContext) | ||
return <> | ||
<h4>Access Token</h4> | ||
<pre>{token}</pre> | ||
</div> | ||
<div> | ||
<h4>Login Information from Access Token (Base64 decoded JWT)</h4> | ||
<h4>User Information from JWT</h4> | ||
<pre>{JSON.stringify(tokenData, null, 2)}</pre> | ||
</div> | ||
</> | ||
) | ||
</> | ||
} | ||
ReactDOM.render( | ||
<div> | ||
<AuthProvider authConfig={authConfig}> | ||
<LoginInfo/> | ||
</AuthProvider> | ||
</div>, document.getElementById('root'), | ||
ReactDOM.render(<AuthProvider authConfig={authConfig}> | ||
<UserInfo/> | ||
</AuthProvider> | ||
, document.getElementById('root'), | ||
) | ||
``` | ||
For more advanced examples, see `./examples/` | ||
## Install | ||
@@ -106,6 +70,23 @@ | ||
and import | ||
## IAuthContext values | ||
```javascript | ||
import { AuthContext, AuthProvider } from "react-oauth2-code-pkce" | ||
The `IAuthContext` interface that the `AuthContext` returns when called with `useContext()` provides these values; | ||
```typescript | ||
interface IAuthContext { | ||
// The access token. This is what you will use for authentication against protected API's | ||
token: string | ||
// An object with all the properties encoded in the token (username, email, etc) | ||
tokenData?: TTokenData | ||
// Login the user | ||
login: () => void | ||
// Logout the user from the auth provider | ||
logOut: () => void | ||
// Keep any errors that occured during login or token fetching/refreshing. | ||
error: string | null | ||
// The idToken, if also that was returned along with the access token | ||
idToken?: string | ||
// If the <AuthProvider> is done fetching tokens or not. Usefull for controlling page rendering | ||
loginInProgress: boolean | ||
} | ||
``` | ||
@@ -115,2 +96,4 @@ | ||
The `<AuthProvider>` takes a `config` object that supports these parameters; | ||
```typescript | ||
@@ -138,2 +121,5 @@ type TAuthConfig = { | ||
postLogin?: () => void // default: () => null | ||
// Optional callback function for the 'refreshTokenExpired' event. | ||
// You likely want to display a message saying the user need to login again | ||
onRefreshTokenExpire?: (event: TRefreshTokenExpiredEvent) => void // default: undefined | ||
// Whether or not to decode the access token (should be set to 'false' if the access token is not a JWT (e.g. from Github)) | ||
@@ -140,0 +126,0 @@ // If `false`, 'tokenData' will be 'undefined' from the <AuthContext> |
31571
592
144