@@ -4,6 +4,8 @@ import { Input } from '@/components/ui/input'
44import { Label } from '@/components/ui/label'
55import { Dialog , DialogContent , DialogDescription , DialogHeader , DialogTitle } from '@/components/ui/dialog'
66import { Loader2 , ExternalLink , CheckCircle } from 'lucide-react'
7+ import { CopyButton } from '@/components/ui/copy-button'
8+ import { showToast } from '@/lib/toast'
79import { oauthApi , type OAuthAuthorizeResponse } from '@/api/oauth'
810import { mapOAuthError } from '@/lib/oauthErrors'
911
@@ -66,6 +68,10 @@ export function OAuthCallbackDialog({
6668
6769 const isAutoMethod = authResponse . method === 'auto'
6870
71+ // Extract device/user code from instructions (e.g., "Enter code: 596A-E304")
72+ const codeMatch = authResponse . instructions . match ( / (?: E n t e r c o d e | U s e r c o d e | D e v i c e c o d e ) [: \s] + ( [ A - Z 0 - 9 - ] + ) / i)
73+ const deviceCode = codeMatch ? codeMatch [ 1 ] : ''
74+
6975 return (
7076 < Dialog open = { open } onOpenChange = { handleClose } >
7177 < DialogContent className = "bg-card border-border max-w-lg" >
@@ -89,20 +95,57 @@ export function OAuthCallbackDialog({
8995 < div className = "space-y-3" >
9096 < div className = "bg-muted p-3 rounded-md" >
9197 < p className = "text-sm mb-2" > { authResponse . instructions } </ p >
92- < Button
93- onClick = { handleOpenAuthUrl }
94- variant = "outline"
95- size = "sm"
96- className = "w-full"
97- >
98- < ExternalLink className = "h-4 w-4 mr-2" />
99- Open Authorization Page
100- </ Button >
98+
99+ { deviceCode && (
100+ < div className = "flex items-center gap-2 mb-3" >
101+ < code className = "flex-1 bg-background px-3 py-2 rounded text-sm font-mono" >
102+ { deviceCode }
103+ </ code >
104+ < CopyButton
105+ content = { deviceCode }
106+ title = "Copy device code"
107+ variant = "ghost"
108+ iconSize = "sm"
109+ className = "flex-shrink-0"
110+ onCopy = { ( ) => showToast . success ( 'Code copied to clipboard' ) }
111+ />
112+ </ div >
113+ ) }
114+
115+ < div className = "flex gap-2" >
116+ < Button
117+ onClick = { handleOpenAuthUrl }
118+ variant = "outline"
119+ size = "sm"
120+ className = "flex-1"
121+ >
122+ < ExternalLink className = "h-4 w-4 mr-2" />
123+ Open Authorization Page
124+ </ Button >
125+ < CopyButton
126+ content = { authResponse . url }
127+ title = "Copy authorization URL"
128+ variant = "ghost"
129+ iconSize = "sm"
130+ className = "flex-shrink-0"
131+ onCopy = { ( ) => showToast . success ( 'URL copied to clipboard' ) }
132+ />
133+ </ div >
101134 </ div >
102135
103136 { ! isAutoMethod && (
104137 < div className = "space-y-2" >
105- < Label htmlFor = "authCode" > Authorization Code</ Label >
138+ < div className = "flex items-center gap-2" >
139+ < Label htmlFor = "authCode" > Authorization Code</ Label >
140+ < CopyButton
141+ content = { authCode }
142+ title = "Copy authorization code"
143+ variant = "ghost"
144+ iconSize = "sm"
145+ className = "flex-shrink-0"
146+ onCopy = { ( ) => showToast . success ( 'Code copied to clipboard' ) }
147+ />
148+ </ div >
106149 < Input
107150 id = "authCode"
108151 value = { authCode }
0 commit comments