bento-auth-js
Version:
Authentication library for web applications of Bento-Platform
81 lines (73 loc) • 2.69 kB
text/typescript
import { createSlice, createAsyncThunk } from "@reduxjs/toolkit";
import { AnyAction } from "redux";
import { ThunkAction } from "redux-thunk";
import { RootState } from "./store";
type OpenIdConfigPayload = {
issuer: string;
authorization_endpoint: string;
end_session_endpoint?: string;
token_endpoint: string;
grant_types_supported: string[];
};
// Async actions using createAsyncThunk
export const fetchOpenIdConfiguration = createAsyncThunk<OpenIdConfigPayload, string>(
"openIdConfig/fetchOpenIdConfiguration",
async (openIdConfigUrl: string, { rejectWithValue }) => {
const response = await fetch(openIdConfigUrl);
if (response.ok) {
return await response.json();
} else {
return rejectWithValue("Could not fetch identity provider configuration");
}
},
{
condition: (_, { getState }) => {
const state = getState() as RootState;
const { isFetching, data, expiry } = state.openIdConfiguration;
return !isFetching && (!data || !expiry || Date.now() > expiry * 1000);
},
},
);
export const fetchOpenIdConfigurationIfNecessary =
(openIdConfigUrl: string): ThunkAction<void, RootState, unknown, AnyAction> =>
async (dispatch, getState) => {
const { isFetching, expiry } = getState().openIdConfiguration;
if (isFetching || (expiry && Date.now() < expiry * 1000)) return;
return dispatch(fetchOpenIdConfiguration(openIdConfigUrl));
};
export type OIDCSliceState = {
isFetching: boolean;
hasAttempted: boolean;
data?: OpenIdConfigPayload;
expiry?: number;
};
const initialState: OIDCSliceState = {
isFetching: false,
hasAttempted: false,
data: undefined,
expiry: undefined,
};
export const openIdConfigSlice = createSlice({
name: "openIdConfiguration",
initialState,
reducers: {},
extraReducers: (builder) => {
builder.addCase(fetchOpenIdConfiguration.pending, (state) => {
state.isFetching = true;
});
builder.addCase(fetchOpenIdConfiguration.fulfilled, (state, { payload }) => {
state.isFetching = false;
state.hasAttempted = true;
state.data = payload;
state.expiry = Date.now() / 1000 + 3 * 60 * 60; // Cache for 3 hours
});
builder.addCase(fetchOpenIdConfiguration.rejected, (state, { error }) => {
console.error(error);
state.isFetching = false;
state.hasAttempted = true;
state.data = undefined;
state.expiry = undefined;
});
},
});
export default openIdConfigSlice.reducer;