Skip to content

Commit

Permalink
Add client authn verification page (#929)
Browse files Browse the repository at this point in the history
* Add client authn verification page

* Update for renamed device auth endpoints

* Bump OMICRON_VERSION

* prove oxidecomputer/omicron#1303 fixes it

* make typescript happy

* use omicron version that's on main now that it's merged

* quick polish on auth and success state

Co-authored-by: David Crespo <[email protected]>
  • Loading branch information
plotnick and david-crespo authored Jun 29, 2022
1 parent 37c7c40 commit a779fe5
Show file tree
Hide file tree
Showing 4 changed files with 82 additions and 0 deletions.
17 changes: 17 additions & 0 deletions app/pages/DeviceAuthSuccessPage.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { Success16Icon } from '@oxide/ui'

/**
* Device authorization success page
*/
export default function DeviceAuthSuccessPage() {
return (
<div className="space-y-4 max-w-sm text-center">
<h1 className="text-sans-2xl">Device authentication</h1>
<h2 className="text-sans-3xl flex items-center text-accent justify-center">
<Success16Icon width={40} height={40} className="mr-3 text-accent" />
Success!
</h2>
<p>Your device is now logged in.</p>
</div>
)
}
48 changes: 48 additions & 0 deletions app/pages/DeviceAuthVerifyPage.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { useNavigate, useSearchParams } from 'react-router-dom'

import { useApiMutation } from '@oxide/api'
import { Button, Warning12Icon } from '@oxide/ui'

import { useToast } from '../hooks'

/**
* Device authorization verification page
*/
export default function DeviceAuthVerifyPage() {
const [searchParams] = useSearchParams()
const navigate = useNavigate()
const addToast = useToast()
const confirmPost = useApiMutation('deviceAuthConfirm', {
onSuccess: () => {
navigate('/device/success')
},
onError: () => {
addToast({
title: 'Token denied',
icon: <Warning12Icon />,
variant: 'error',
timeout: 4000,
})
},
})
const userCode = searchParams.get('user_code')

return (
<div className="space-y-4 max-w-sm text-center">
<h1 className="text-sans-2xl">Device authentication</h1>
<p>Make sure this code matches the one shown on the device you are authenticating.</p>
<h2 className="text-sans-3xl border p-4">{userCode}</h2>
<Button
className="w-full"
disabled={confirmPost.isLoading || confirmPost.isSuccess || !userCode}
onClick={() => {
// we know `userCode` is non-null because the button is disabled
// otherwise, but let's make TS happy
if (userCode) confirmPost.mutate({ body: { userCode } })
}}
>
Log in on device
</Button>
</div>
)
}
7 changes: 7 additions & 0 deletions app/routes.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import OrgLayout from './layouts/OrgLayout'
import ProjectLayout from './layouts/ProjectLayout'
import RootLayout from './layouts/RootLayout'
import SettingsLayout from './layouts/SettingsLayout'
import DeviceAuthSuccessPage from './pages/DeviceAuthSuccessPage'
import DeviceAuthVerifyPage from './pages/DeviceAuthVerifyPage'
import LoginPage from './pages/LoginPage'
import NotFound from './pages/NotFound'
import { OrgAccessPage } from './pages/OrgAccessPage'
Expand Down Expand Up @@ -44,6 +46,11 @@ export const Router = () => (
<Route index element={<LoginPage />} />
</Route>

<Route path="device" element={<AuthLayout />}>
<Route path="verify" element={<DeviceAuthVerifyPage />} />
<Route path="success" element={<DeviceAuthSuccessPage />} />
</Route>

<Route index element={<Navigate to="/orgs" replace />} />

<Route path="orgs" errorElement={<RouterDataErrorBoundary />}>
Expand Down
10 changes: 10 additions & 0 deletions libs/api-mocks/msw/handlers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -875,4 +875,14 @@ export const handlers = [
rest.get<never, never, Json<Api.UserResultsPage> | GetErr>('/api/users', (req, res) => {
return res(json(paginated(req.url.search, db.users)))
}),

rest.post<Json<Api.DeviceAuthVerify>, never, PostErr>(
'/api/device/confirm',
(req, res, ctx) => {
if (req.body.user_code === 'BADD-CODE') {
return res(ctx.status(404))
}
return res(ctx.status(200))
}
),
]

1 comment on commit a779fe5

@vercel
Copy link

@vercel vercel bot commented on a779fe5 Jun 29, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@plotnick is attempting to deploy a commit to the Oxide Computer Company Team on Vercel.

To accomplish this, @plotnick needs to request access to the Team.

Afterwards, an owner of the Team is required to accept their membership request.

If you're already a member of the respective Vercel Team, make sure that your Personal Vercel Account is connected to your GitHub account.

Please sign in to comment.