Skip to content

Commit

Permalink
feat: add mobile login handler (#1207)
Browse files Browse the repository at this point in the history
* feat: add mobile login handler
* chore: fix user mgmt code due to auth0 lib upgrade
* chore: remove dead code
  • Loading branch information
vnugent authored Nov 11, 2024
1 parent 51375e5 commit bf4c61f
Show file tree
Hide file tree
Showing 22 changed files with 227 additions and 1,448 deletions.
2 changes: 1 addition & 1 deletion .env
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ AUTH0_CLIENT_SECRET=send request to hello at openbeta.io
NEXTAUTH_SECRET=vQyFR7gskaqxehN0cI/53r+duWc5Et0ktdoz6KozTCo=

# Auth0 Management API
AUTH0_MGMT_CLIENT_ID=seD3dNxnZ4jXik1dzdQEgPSNSvXGBsqA
AUTH0_MGMT_CLIENT_ID=Ecyj4oke3Cpk1khRsdKr8njen6ZZKePF
AUTH0_MGMT_CLIENT_SECRET=send request to hello at openbeta.io

######### Client-side vars ############
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
"@turf/line-to-polygon": "^6.5.0",
"@udecode/zustood": "^1.1.3",
"@vercel/edge": "^1.1.1",
"auth0": "^2.42.0",
"auth0": "^4.12.0",
"awesome-debounce-promise": "^2.1.0",
"axios": "^0.24.0",
"classnames": "^2.3.1",
Expand Down
2 changes: 2 additions & 0 deletions src/Config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ interface AUTH_CONFIG_SERVER_TYPE {
clientSecret: string
mgmtClientId: string
mgmtClientSecret: string
mgmtClientAudience: string
nextauthSecret: string
}

Expand All @@ -26,6 +27,7 @@ if (typeof window === 'undefined') {
clientSecret: checkAndPrintWarning('AUTH0_CLIENT_SECRET', process.env.AUTH0_CLIENT_SECRET),
mgmtClientId: checkAndPrintWarning('AUTH0_MGMT_CLIENT_ID', process.env.AUTH0_MGMT_CLIENT_ID),
mgmtClientSecret: checkAndPrintWarning('AUTH0_MGMT_CLIENT_SECRET', process.env.AUTH0_MGMT_CLIENT_SECRET),
mgmtClientAudience: checkAndPrintWarning('AUTH0_MGMT_CLIENT_AUDIENCE', process.env.AUTH0_MGMT_CLIENT_AUDIENCE),
nextauthSecret: checkAndPrintWarning('NEXTAUTH_SECRET', process.env.NEXTAUTH_SECRET)
}
} else {
Expand Down
40 changes: 40 additions & 0 deletions src/app/api/mobile/login/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { NextRequest, NextResponse } from 'next/server'
import * as Auth0 from 'auth0'
import { auth0Client, isNullOrEmpty } from '@/js/auth/mobile'
import { withMobileAuth } from '@/js/auth/withMobileAuth'

/**
* Mobile login handler
*/
async function postHandler (request: NextRequest): Promise<NextResponse> {
let username: string, password: string
try {
const data = await request.json()
username = data.username
password = data.password

if (isNullOrEmpty(username) || isNullOrEmpty(password)) {
console.error('Empty username/password!')
throw new Error('Invalid payload')
}
} catch (error) {
return NextResponse.json({ error: 'Unexpected error', status: 400 })
}

let response: Auth0.JSONApiResponse<Auth0.TokenSet> | undefined
try {
response = await auth0Client.oauth.passwordGrant({
username,
password,
scope: 'openid profile email offline_access',
audience: 'https://api.openbeta.io'
})

return NextResponse.json({ data: response.data })
} catch (error) {
console.error('#### Auth0 error ####', error)
return NextResponse.json({ error: 'Unexpected auth error', status: 403 })
}
}

export const POST = withMobileAuth(postHandler)
37 changes: 37 additions & 0 deletions src/app/api/mobile/refreshToken/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { NextRequest, NextResponse } from 'next/server'
import * as Auth0 from 'auth0'
import { auth0Client, isNullOrEmpty } from '@/js/auth/mobile'
import { withMobileAuth } from '@/js/auth/withMobileAuth'

/**
* Mobile refresh token handler
*/
async function postHandler (request: NextRequest): Promise<any> {
let refreshToken: string
try {
const data = await request.json()
refreshToken = data.refreshToken

if (isNullOrEmpty(refreshToken)) {
console.error('Empty refreshToken!')
throw new Error('Invalid payload')
}
} catch (error) {
return NextResponse.json({ error: 'Unexpected error', status: 400 })
}

let response: Auth0.JSONApiResponse<Auth0.TokenSet> | undefined
try {
response = await auth0Client.oauth.refreshTokenGrant({
refresh_token: refreshToken,
audience: 'https://api.openbeta.io'
})

return NextResponse.json({ data: response.data })
} catch (error) {
console.error('#### Auth0 error ####', error)
return NextResponse.json({ error: 'Unexpected auth error', status: 403 })
}
}

export const POST = withMobileAuth(postHandler)
79 changes: 0 additions & 79 deletions src/components/area/panel/panelList.tsx

This file was deleted.

86 changes: 0 additions & 86 deletions src/components/area/panel/sidePanel.tsx

This file was deleted.

10 changes: 5 additions & 5 deletions src/components/basecamp/UserForm.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
import type { User } from 'auth0'
import type { UserProfile } from 'auth0'
import clx from 'classnames'
import { TextArea } from '../ui/form'
import { useForm, FormProvider } from 'react-hook-form'
import { MUUID_VALIDATION, conjoinedStringToArray } from './utils'
import axios from 'axios'
import useSWR from 'swr'
import { Role } from 'auth0'
import { UserInfoResponse } from 'auth0'
import { UserRole } from '../../js/types'
import MultiSelect from '../ui/form/MultiSelect'
import { useEffect } from 'react'

interface UserFormProps {
user: User
user: UserProfile
onClose: () => void
}

Expand All @@ -26,11 +26,11 @@ const fetcher = async (url: string): Promise<any> => (await axios.get(url)).data
* Form for updating users.
*/
export default function UserForm ({ user, onClose }: UserFormProps): JSX.Element {
const userId = user.user_id
const userId = user.user_id as string
if (userId == null) {
return <div>Can't load user. Missing user_id.</div>
}
const { data: roles, error, mutate } = useSWR<Role[]>(`/api/basecamp/userRoles?userId=${userId}`, fetcher)
const { data: roles, error, mutate } = useSWR<UserInfoResponse[]>(`/api/basecamp/userRoles?userId=${userId}`, fetcher)
if (error != null) {
return <div>{error}</div>
}
Expand Down
12 changes: 6 additions & 6 deletions src/components/basecamp/Users.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,15 @@ import { formatDistanceToNow, parseISO } from 'date-fns'
import { useSession, signIn } from 'next-auth/react'
import useSWR from 'swr'
import axios from 'axios'
import { UserPage } from 'auth0'
import { GetUsers200ResponseOneOf, GetUsers200ResponseOneOfInner } from 'auth0'

import { MagnifyingGlassIcon, PencilSquareIcon } from '@heroicons/react/20/solid'
import { IUserMetadata, UserRole } from '../../js/types/User'
import { usersToCsv, saveAsCSVFile } from '../../js/utils/csv'
import { CLIENT_CONFIG } from '../../js/configs/clientConfig'
import { Input } from '../ui/form'
import { useForm, FormProvider } from 'react-hook-form'
import type { User } from 'auth0'
import type { UserProfile } from 'auth0'
import CreateUpdateModal from './CreateUpdateModal'
import UserForm from './UserForm'
import { RulesType } from '../../js/types'
Expand Down Expand Up @@ -55,7 +55,7 @@ const UserTable = (): JSX.Element => {
const [currentPage, setPage] = useState(0)
const [emailFilter, setEmailFilter] = useState('')
const [modalOpen, setModalOpen] = useState(false)
const [focussedUser, setFocussedUser] = useState<User | null>(null)
const [focussedUser, setFocussedUser] = useState<UserProfile | null>(null)

// React-hook-form declaration
const form = useForm<HtmlFormProps>({
Expand All @@ -67,7 +67,7 @@ const UserTable = (): JSX.Element => {
const { handleSubmit } = form
const submitHandler = ({ email }: HtmlFormProps): void => { setEmailFilter(email) }

const { isLoading, data: userPage, error, mutate } = useSWR<UserPage>(`/api/basecamp/users?page=${currentPage}&email=${emailFilter}&type=auth0`, fetcher)
const { isLoading, data: userPage, error, mutate } = useSWR<GetUsers200ResponseOneOf>(`/api/basecamp/users?page=${currentPage}&email=${emailFilter}&type=auth0`, fetcher)
if (isLoading) return <div className='my-8>'>Loading...</div>

const totalPages = Math.ceil((userPage?.total ?? 0) / (userPage?.limit ?? 0))
Expand Down Expand Up @@ -144,7 +144,7 @@ const UserTable = (): JSX.Element => {
interface UserRowProps {
index: number
user: any
setFocussedUser: (arg0: User) => void
setFocussedUser: (arg0: GetUsers200ResponseOneOfInner) => void
setModalOpen: (arg0: boolean) => void
}

Expand Down Expand Up @@ -182,7 +182,7 @@ const UserRow = ({ index, user, setFocussedUser, setModalOpen }: UserRowProps):

const PasswordlessUsers = (): JSX.Element => {
const [currentPage, setPage] = useState(0)
const { data: userPage } = useSWR<UserPage>(`/api/basecamp/users?page=${currentPage}&type=email`, fetcher)
const { data: userPage } = useSWR<GetUsers200ResponseOneOf>(`/api/basecamp/users?page=${currentPage}&type=email`, fetcher)

const onClickHandler = (userId: string): void => {
void axios.get(`/api/basecamp/migrate?id=${userId}`)
Expand Down
Loading

0 comments on commit bf4c61f

Please sign in to comment.