react-ketting
Version:
Ketting bindings for React
162 lines • 7.18 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.RequireLogin = void 0;
const React = require("react");
const use_client_1 = require("../hooks/use-client");
const ketting_1 = require("ketting");
const { useEffect, useState } = React;
const LOCALSTORAGEKEY = 'ketting-auth:3';
/**
* The RequireLogin component ensures that a user is authenticated.
*
* Children will not be rendered until this is the case.
*/
const RequireLogin = (props) => {
const [isAuthenticated, setAuthenticated] = useState(false);
const client = (0, use_client_1.useClient)();
const validateToken = async () => {
const location = new URL(document.location.href);
if (location.search) {
// If we have a 'code' query parameter, the client will attempt to authenticate with
// the code via oauth2 and attempt to redirect back to your url
const searchParams = new URLSearchParams(location.search.substr(1));
if (searchParams.has('code')) {
const code = searchParams.get('code');
// This 'state' is the OAuth2 state, and we're using it to put a
// relative url where the user needs to go (in app) after
// authentication.
const state = searchParams.get('state') || null;
await processCodeFromUrl(code, state);
return;
}
}
// If we got this far in the function, there was no 'code' in the url.
// Lets check if we have credentials in LocalStorage.
const localStorageAuth = window.localStorage.getItem(LOCALSTORAGEKEY);
if (localStorageAuth) {
// this doesnt feel like a good variable name
const parsedToken = JSON.parse(localStorageAuth);
client.use((0, ketting_1.oauth2)({
grantType: undefined,
clientId: props.clientId,
tokenEndpoint: props.tokenEndpoint,
onTokenUpdate: (token) => storeKettingCredentialsInLocalStorage(token),
onAuthError: err => {
console.error('[ketting] Got a deep 401 error, lets re-authenticate');
// IF we got here it means we didn't have tokens in LocalStorage, or they
// were expired.
document.location.href = getAuthorizeUri(props);
}
}, parsedToken));
// Lets test auth.
try {
if (props.testEndpoint === null) {
console.info('[ketting] Using stored credentials. testEndpoint is disabled.');
setAuthenticated(true);
}
else {
const testResource = client.go(props.testEndpoint);
console.info('[ketting] Testing stored credentials on %s', testResource.uri);
await testResource.get();
console.info('[ketting] Stored credentials were accepted');
// Authentication succeeded
setAuthenticated(true);
// End function
return;
}
}
catch (err) {
switch (err.httpCode) {
case 400:
if (err.oauth2Code === 'invalid_grant') {
console.info('Refresh token might already have been used, or invalid or expired. Lets re-authenticate');
}
else {
console.error('[ketting] ', err);
throw new Error('Got error while accessing api: ' + err.httpCode);
}
break;
case 401:
console.info('[ketting] Stored credentials were not valid. Lets re-authenticate');
break;
default:
console.error('[ketting] ', err);
throw new Error('Got error while accessing api: ' + err.httpCode);
}
}
}
else {
console.info('[ketting] No stored credentials. Redirecting to auth API api');
}
// IF we got here it means we didn't have tokens in LocalStorage, or they
// were expired.
document.location.href = getAuthorizeUri(props);
};
useEffect(() => {
validateToken().catch(err => {
console.error('[ketting] Error while validating token', err);
});
}, [client]);
if (isAuthenticated) {
return React.createElement(React.Fragment, null, props.children);
}
/**
* This function gets called when we get redirected back from a OAuth2
* authorization endpoint.
*/
const processCodeFromUrl = async (code, state) => {
client.use((0, ketting_1.oauth2)({
grantType: 'authorization_code',
clientId: props.clientId,
tokenEndpoint: props.tokenEndpoint,
redirectUri: document.location.origin + '/',
code: code,
onTokenUpdate: (token) => storeKettingCredentialsInLocalStorage(token),
onAuthError: err => {
console.error('[ketting] Got a deep 401 error, lets re-authenticate');
// IF we got here it means we didn't have tokens in LocalStorage, or they
// were expired.
document.location.href = getAuthorizeUri(props);
}
}));
// Lets test authentication.
try {
await client.go().get();
}
catch (err) {
throw new Error('Error from API after authenticating: ' + err);
}
setAuthenticated(true);
props.onSuccess(state);
};
const storeKettingCredentialsInLocalStorage = async (token) => {
// Store credentials.
// ? Should this be custom-set by the user?
window.localStorage.setItem(LOCALSTORAGEKEY, JSON.stringify(token));
};
// We return a generic "Authenticating" component while the useEffect is...in effect
// A custom "authenticating" component can also be passed in instead
return (React.createElement(React.Fragment, null, props.authenticatingComponent ?
(props.authenticatingComponent)
:
(React.createElement("div", { className: 'authenticating' },
React.createElement("header", null,
React.createElement("h1", null, "Authenticating"))))));
};
exports.RequireLogin = RequireLogin;
/**
* Generates the full URL to redirect the user to for the OAuth2 authorization
* endpoint.
*/
function getAuthorizeUri(props) {
const currentRoot = document.location.origin + '/';
const currentPath = document.location.pathname;
const params = new URLSearchParams([
['response_type', 'code'],
['client_id', props.clientId],
['redirect_uri', currentRoot],
['state', currentPath],
]);
return props.authorizeEndpoint + '?' + params.toString();
}
//# sourceMappingURL=RequireLogin.js.map