-
Notifications
You must be signed in to change notification settings - Fork 53
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
0c88533
commit 6cf57d7
Showing
5 changed files
with
188 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,113 @@ | ||
import React, {useState} from 'react'; | ||
import PropTypes from 'prop-types'; | ||
import {Button} from '../generic'; | ||
import Spinner from '../generic/Spinner/Spinner'; | ||
|
||
/** | ||
* Performs OAuth 2.0 Authorization | ||
* | ||
* @param {object} props Data passed to the component | ||
* @param {string} props.authUrl Authorization url | ||
* @param {string} props.clientID Client ID of the app | ||
* @param {string} props.redirectUri Redirect Url registered to capture the code | ||
* @param {string} props.scope Scope required for the app | ||
* @param {Function} props.signInResponse Function called on successfull sign in | ||
* @param {Function} props.getAccessToken Function called to fetch access token from backend server | ||
* @param {object} props.tokenStoragePolicy Store token in cookie, local or session storage | ||
* @param {string} props.authType Authorization server type | ||
* @returns {object} JSX of the component | ||
*/ | ||
export default function SignIn({ | ||
authUrl, | ||
clientID, | ||
redirectUri, | ||
authType, | ||
scope, | ||
signInResponse, | ||
getAccessToken, | ||
tokenStoragePolicy, | ||
}) { | ||
const [isAuthenticating, setIsAuthenticating] = useState(false); | ||
|
||
const openAuthUrl = () => { | ||
const arr = new Uint8Array(4); | ||
const state = window.crypto.getRandomValues(arr); | ||
const fullAuthUrl = `${authUrl}?client_id=${clientID}&response_type=code&redirect_uri=${encodeURI(redirectUri)}${scope !== '' ? `&scope=${encodeURI(scope)}` : ''}&state=${state}`; | ||
|
||
const newWindow = window.open(fullAuthUrl, 'targetWindow', 'toolbar=no,location=no,status=no,menubar=no,scrollbars=yes,resizable=yes,width=400,height=700'); | ||
|
||
setIsAuthenticating(true); | ||
|
||
if (authType === 'Custom') { | ||
const timer = setInterval(() => { | ||
if (newWindow.closed) { | ||
clearInterval(timer); | ||
getAccessToken().then((accessToken) => { | ||
if (accessToken) { | ||
if (Object.keys(tokenStoragePolicy).length !== 0) { | ||
const {name, place, ttl} = tokenStoragePolicy; | ||
|
||
switch (place) { | ||
case 'cookie': { | ||
const expiry = new Date(); | ||
|
||
expiry.setSeconds(ttl); | ||
document.cookie = `${name}=${accessToken}; secure; expires=${expiry.toUTCString()}`; | ||
break; | ||
} | ||
case 'session': | ||
sessionStorage.setItem(name, accessToken); | ||
break; | ||
case 'local': | ||
localStorage.setItem(name, accessToken); | ||
break; | ||
default: | ||
break; | ||
} | ||
} | ||
} | ||
signInResponse(clientID, accessToken || Error('No access token was returned')); | ||
}) | ||
.catch((err) => { | ||
signInResponse(clientID, Error('Failed to fetch access token: ', err)); | ||
}); | ||
setIsAuthenticating(false); | ||
} | ||
}, 500); | ||
} | ||
}; | ||
|
||
return ( | ||
<div className="sign-in-wrapper"> | ||
{isAuthenticating ? <Spinner /> : ( | ||
<Button | ||
type="join" | ||
size={40} | ||
onClick={openAuthUrl} | ||
> | ||
Sign In | ||
</Button> | ||
)} | ||
</div> | ||
); | ||
} | ||
|
||
SignIn.propTypes = { | ||
authUrl: PropTypes.string.isRequired, | ||
clientID: PropTypes.string.isRequired, | ||
redirectUri: PropTypes.string.isRequired, | ||
authType: PropTypes.string.isRequired, | ||
scope: PropTypes.string, | ||
signInResponse: PropTypes.func, | ||
getAccessToken: PropTypes.func, | ||
tokenStoragePolicy: PropTypes.shape( | ||
{place: PropTypes.string, name: PropTypes.string, ttl: PropTypes.number}, | ||
), | ||
}; | ||
|
||
SignIn.defaultProps = { | ||
scope: '', | ||
signInResponse: () => {}, | ||
getAccessToken: () => {}, | ||
tokenStoragePolicy: {}, | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
import React from 'react'; | ||
import SignIn from './SignIn'; | ||
|
||
export default { | ||
title: 'Platform/Sign In', | ||
component: SignIn, | ||
}; | ||
|
||
const Template = (args) => <SignIn {...args} />; | ||
|
||
export const WebexAuth = Template.bind({}); | ||
WebexAuth.args = { | ||
authUrl: 'https://webexapis.com/v1/authorize', | ||
responseType: 'code', | ||
clientID: process.env.webex_int_client_id, | ||
redirectUri: 'http://example.com/verification', | ||
scope: process.env.webex_int_scope, | ||
authType: 'Custom', | ||
signInResponse: (clientID, accessToken) => `Example: Send access token as props to create space: ${clientID === process.env.webex_int_client_id ? accessToken : ''}`, | ||
getAccessToken: () => fetch('http://example.com/access_token').then((res) => { | ||
if (res?.data?.access_token) { | ||
return res.data.accessToken; | ||
} | ||
|
||
throw Error('Failed to fetch access token'); | ||
}), | ||
tokenStoragePolicy: {place: 'cookie', name: 'integ_cookie', ttl: 1209600}, | ||
}; |
45 changes: 45 additions & 0 deletions
45
src/components/SignIn/__snapshots__/SignIn.stories.storyshot
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
// Jest Snapshot v1, https://goo.gl/fbAQLP | ||
|
||
exports[`Storyshots Platform/Sign In Webex Auth 1`] = ` | ||
Array [ | ||
<div | ||
className="sign-in-wrapper" | ||
> | ||
<button | ||
autoFocus={false} | ||
className="wxc wxc-button wxc-button--join" | ||
onClick={[Function]} | ||
style={ | ||
Object { | ||
"height": 40, | ||
} | ||
} | ||
tabIndex={0} | ||
type="button" | ||
> | ||
Sign In | ||
</button> | ||
|
||
</div>, | ||
<video | ||
autoPlay={true} | ||
height="0" | ||
id="remote-video" | ||
loop={true} | ||
muted={true} | ||
playsInline={true} | ||
src="./video/ongoing-meeting.mp4" | ||
width="0" | ||
/>, | ||
<video | ||
autoPlay={true} | ||
height="0" | ||
id="remote-share" | ||
loop={true} | ||
muted={true} | ||
playsInline={true} | ||
src="./video/ongoing-share.mp4" | ||
width="0" | ||
/>, | ||
] | ||
`; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters