This repository has been archived by the owner on Apr 10, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* chore: rename hooks; cleanup * chore: remove auth provider * chore: rename hooks back * chore: forgot to stage renamed files * feat(auth): wip * chore: add include creds everywhere; create delete helper func * chore: wip login * chore: wip * chore: wip * chore: wip fix auth * chore: load self data * feat: load user profile * chore: fix login redirect when auth not required * chore: rename session, fix exhaustive deps issue * fix: api calls * chore: show name on hover * chore: get images working in dev mode; opacity on user ring * feat: implement logout * feat: add known providers/icons * chore: set session null on logout * chore: rm credentials include * fix: linter warning * fix: loading of providers * fix: login page * fix: session infinite loop * feat(api): add CSRF token support * fix: show empty user if no imageURL * fix: set headers * fix: try to fix these loadeffect loops * chore: disable refresh interval in swr * fix(csrf): drop type constraints on setCsrf * chore: make login dynamic import Co-authored-by: George MacRorie <me@georgemac.com>
- Loading branch information
1 parent
96b3a78
commit 86acc1c
Showing
15 changed files
with
525 additions
and
139 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
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
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,155 @@ | ||
import { | ||
faGitlab, | ||
faGoogle, | ||
faOpenid | ||
} from '@fortawesome/free-brands-svg-icons'; | ||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; | ||
import { toLower, upperFirst } from 'lodash'; | ||
import { useEffect, useState } from 'react'; | ||
import { Navigate } from 'react-router-dom'; | ||
import logoFlag from '~/assets/logo-flag.png'; | ||
import { listAuthMethods } from '~/data/api'; | ||
import { useError } from '~/data/hooks/error'; | ||
import { useSession } from '~/data/hooks/session'; | ||
import { AuthMethod, AuthMethodOIDC } from '~/types/Auth'; | ||
|
||
interface ILoginProvider { | ||
displayName: string; | ||
icon?: any; | ||
} | ||
|
||
const knownProviders: Record<string, ILoginProvider> = { | ||
google: { | ||
displayName: 'Google', | ||
icon: faGoogle | ||
}, | ||
gitlab: { | ||
displayName: 'GitLab', | ||
icon: faGitlab | ||
}, | ||
auth0: { | ||
displayName: 'Auth0' | ||
} | ||
}; | ||
|
||
export default function Login() { | ||
const { session } = useSession(); | ||
|
||
const [providers, setProviders] = useState< | ||
{ | ||
name: string; | ||
authorize_url: string; | ||
callback_url: string; | ||
icon: any; | ||
}[] | ||
>([]); | ||
|
||
const { setError, clearError } = useError(); | ||
|
||
const authorize = async (uri: string) => { | ||
const res = await fetch(uri, { | ||
method: 'GET', | ||
headers: { | ||
'Content-Type': 'application/json' | ||
} | ||
}); | ||
|
||
if (!res.ok || res.status !== 200) { | ||
setError(new Error('Unable to authenticate: ' + res.text())); | ||
return; | ||
} | ||
|
||
clearError(); | ||
const body = await res.json(); | ||
window.location.href = body.authorizeUrl; | ||
}; | ||
|
||
useEffect(() => { | ||
const loadProviders = async () => { | ||
try { | ||
const resp = await listAuthMethods(); | ||
// TODO: support alternative auth methods | ||
const authOIDC = resp.methods.find( | ||
(m: AuthMethod) => m.method === 'METHOD_OIDC' && m.enabled | ||
) as AuthMethodOIDC; | ||
|
||
if (!authOIDC) { | ||
return; | ||
} | ||
|
||
const loginProviders = Object.entries(authOIDC.metadata.providers).map( | ||
([k, v]) => { | ||
k = toLower(k); | ||
return { | ||
name: knownProviders[k]?.displayName || upperFirst(k), // if we dont know the provider, just capitalize the first letter | ||
authorize_url: v.authorize_url, | ||
callback_url: v.callback_url, | ||
icon: knownProviders[k]?.icon || faOpenid // if we dont know the provider icon, use the openid icon | ||
}; | ||
} | ||
); | ||
setProviders(loginProviders); | ||
} catch (err) { | ||
setError(err instanceof Error ? err : Error(String(err))); | ||
} | ||
}; | ||
|
||
loadProviders(); | ||
}, [setProviders, setError]); | ||
|
||
if (session) { | ||
return <Navigate to="/" />; | ||
} | ||
|
||
return ( | ||
<> | ||
<div className="flex min-h-screen flex-col justify-center sm:px-6 lg:px-8"> | ||
<main className="flex px-6 py-10"> | ||
<div className="w-full overflow-x-auto px-4 sm:px-6 lg:px-8"> | ||
<div className="sm:mx-auto sm:w-full sm:max-w-md"> | ||
<img | ||
src={logoFlag} | ||
alt="logo" | ||
width={512} | ||
height={512} | ||
className="m-auto h-20 w-auto" | ||
/> | ||
<h2 className="mt-6 text-center text-3xl font-bold tracking-tight text-gray-900"> | ||
Login to Flipt | ||
</h2> | ||
</div> | ||
|
||
<div className="mt-8 sm:mx-auto sm:w-full sm:max-w-sm"> | ||
<div className="py-8 px-4 sm:px-10"> | ||
<div className="mt-6 flex flex-col space-y-5"> | ||
{providers.map((provider) => ( | ||
<div key={provider.name}> | ||
<a | ||
href="#" | ||
className="inline-flex w-full justify-center rounded-md border border-gray-300 bg-white py-2 px-4 text-sm font-medium text-gray-500 shadow-sm hover:text-violet-500 hover:shadow-violet-300" | ||
onClick={(e) => { | ||
e.preventDefault(); | ||
authorize(provider.authorize_url); | ||
}} | ||
> | ||
<span className="sr-only"> | ||
Sign in with {provider.name} | ||
</span> | ||
<FontAwesomeIcon | ||
icon={provider.icon} | ||
className="text-gray h-5 w-5" | ||
aria-hidden={true} | ||
/> | ||
<span className="ml-2">With {provider.name}</span> | ||
</a> | ||
</div> | ||
))} | ||
</div> | ||
</div> | ||
</div> | ||
</div> | ||
</main> | ||
</div> | ||
</> | ||
); | ||
} |
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
Oops, something went wrong.