@@ -10,7 +10,7 @@ import { CheckCircle2, GalleryVerticalEnd } from 'lucide-react';
1010
1111export const Route = createFileRoute ( '/auth/device' ) ( {
1212 validateSearch : ( search : Record < string , unknown > ) => ( {
13- code : ( search . code as string ) ?? '' ,
13+ user_code : ( search . user_code as string ) ?? ( search . code as string ) ?? '' ,
1414 } ) ,
1515 component : DeviceAuthPage ,
1616} ) ;
@@ -32,12 +32,14 @@ function PageShell({ children }: { children: React.ReactNode }) {
3232}
3333
3434function DeviceAuthPage ( ) {
35- const { code } = Route . useSearch ( ) ;
35+ const { user_code : code } = Route . useSearch ( ) ;
3636 const { user, loading } = useSession ( ) ;
3737 const navigate = useNavigate ( ) ;
3838
3939 const [ submitting , setSubmitting ] = useState ( false ) ;
40+ const [ denying , setDenying ] = useState ( false ) ;
4041 const [ approved , setApproved ] = useState ( false ) ;
42+ const [ denied , setDenied ] = useState ( false ) ;
4143 const [ error , setError ] = useState ( '' ) ;
4244
4345 if ( ! code ) {
@@ -46,7 +48,7 @@ function DeviceAuthPage() {
4648 < Card >
4749 < CardHeader className = "text-center" >
4850 < CardTitle > Invalid Request</ CardTitle >
49- < CardDescription > No device code provided. Please re-run the CLI command.</ CardDescription >
51+ < CardDescription > No user code provided. Please re-run the CLI command.</ CardDescription >
5052 </ CardHeader >
5153 </ Card >
5254 </ PageShell >
@@ -66,7 +68,7 @@ function DeviceAuthPage() {
6668 }
6769
6870 if ( ! user ) {
69- return < Navigate to = "/login" search = { { redirect : `/auth/device?code =${ encodeURIComponent ( code ) } ` } } /> ;
71+ return < Navigate to = "/login" search = { { redirect : `/auth/device?user_code =${ encodeURIComponent ( code ) } ` } } /> ;
7072 }
7173
7274 if ( approved ) {
@@ -83,23 +85,33 @@ function DeviceAuthPage() {
8385 ) ;
8486 }
8587
88+ if ( denied ) {
89+ return (
90+ < PageShell >
91+ < Card >
92+ < CardHeader className = "text-center" >
93+ < CardTitle > Request Denied</ CardTitle >
94+ < CardDescription > The CLI login request has been denied.</ CardDescription >
95+ </ CardHeader >
96+ </ Card >
97+ </ PageShell >
98+ ) ;
99+ }
100+
86101 const handleApprove = async ( ) => {
87102 setError ( '' ) ;
88103 setSubmitting ( true ) ;
89104 try {
90- const sessionRes = await fetch ( '/api/v1/auth/get-session' , { credentials : 'include' } ) ;
91- const sessionData = await sessionRes . json ( ) as any ;
92- const token = sessionData ?. session ?. token ;
93- if ( ! token ) throw new Error ( 'No active session' ) ;
94-
95105 const res = await fetch ( '/api/v1/auth/device/approve' , {
96106 method : 'POST' ,
97107 headers : { 'Content-Type' : 'application/json' } ,
98108 credentials : 'include' ,
99- body : JSON . stringify ( { code , token } ) ,
109+ body : JSON . stringify ( { userCode : code } ) ,
100110 } ) ;
101- const data = await res . json ( ) as any ;
102- if ( ! data . success ) throw new Error ( data . error ?. message ?? 'Approval failed' ) ;
111+ if ( ! res . ok ) {
112+ const data = await res . json ( ) . catch ( ( ) => ( { } ) ) ;
113+ throw new Error ( ( data as any ) ?. message ?? ( data as any ) ?. error ?. message ?? 'Approval failed' ) ;
114+ }
103115
104116 setApproved ( true ) ;
105117 toast ( { title : 'CLI login approved' , description : 'The CLI has been authenticated.' } ) ;
@@ -110,6 +122,24 @@ function DeviceAuthPage() {
110122 }
111123 } ;
112124
125+ const handleDeny = async ( ) => {
126+ setError ( '' ) ;
127+ setDenying ( true ) ;
128+ try {
129+ await fetch ( '/api/v1/auth/device/deny' , {
130+ method : 'POST' ,
131+ headers : { 'Content-Type' : 'application/json' } ,
132+ credentials : 'include' ,
133+ body : JSON . stringify ( { userCode : code } ) ,
134+ } ) ;
135+ setDenied ( true ) ;
136+ } catch ( err : any ) {
137+ setError ( err ?. message ?? 'Deny failed' ) ;
138+ } finally {
139+ setDenying ( false ) ;
140+ }
141+ } ;
142+
113143 return (
114144 < PageShell >
115145 < Card >
@@ -119,7 +149,7 @@ function DeviceAuthPage() {
119149 </ CardHeader >
120150 < CardContent className = "space-y-4" >
121151 < div className = "rounded-md border bg-background px-4 py-3 text-center" >
122- < p className = "text-xs text-muted-foreground mb-1" > Device Code</ p >
152+ < p className = "text-xs text-muted-foreground mb-1" > User Code</ p >
123153 < p className = "font-mono font-semibold tracking-widest text-lg" > { code } </ p >
124154 </ div >
125155
@@ -128,9 +158,12 @@ function DeviceAuthPage() {
128158 Logged in as < span className = "font-medium text-foreground" > { user . email } </ span >
129159 </ p >
130160 { error && < p className = "text-sm text-destructive text-center" > { error } </ p > }
131- < Button onClick = { handleApprove } className = "w-full" disabled = { submitting } >
161+ < Button onClick = { handleApprove } className = "w-full" disabled = { submitting || denying } >
132162 { submitting ? 'Approving…' : 'Approve CLI Access' }
133163 </ Button >
164+ < Button onClick = { handleDeny } variant = "outline" className = "w-full" disabled = { submitting || denying } >
165+ { denying ? 'Denying…' : 'Deny' }
166+ </ Button >
134167 < div className = "text-center" >
135168 < button
136169 type = "button"
0 commit comments