OAuth Authentication
Third-party OAuth authentication supporting Google, GitHub, and other providers.
How It Works
OAuth provides single sign-on (SSO) capabilities:
- User clicks "Sign in with Provider"
- Redirects to provider's authorization page
- User authorizes application
- Provider redirects back with authorization code
- Exchange code for De. access token
Supported Providers: Google, GitHub, Microsoft, Apple
OAuth Flow
1
Initiate OAuth
Redirect user to provider
typescript
// Generate authorization URL
GET https://auth.dedot.io/v1/auth/oauth/{provider}/authorize?redirect_uri={your_redirect_uri}
// Example for Google
https://auth.dedot.io/v1/auth/oauth/google/authorize?redirect_uri=https://yourapp.com/auth/callbackResponse: HTTP 302 redirect to provider's authorization page
2
Handle Callback
Exchange code for token
After user authorizes, provider redirects to your redirect_uri with authorization code:
https://yourapp.com/auth/callback?code=AUTH_CODE&state=STATEExchange the code for De. access token:
typescript
POST https://auth.dedot.io/v1/auth/oauth/{provider}/callback
{
"code": "AUTH_CODE",
"redirectUri": "https://yourapp.com/auth/callback"
}Response:
json
{
"success": true,
"accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"refreshToken": "refresh_token_here",
"expiresIn": 3600,
"user": {
"id": "usr_123456",
"email": "[email protected]",
"name": "John Doe",
"avatar": "https://lh3.googleusercontent.com/...",
"provider": "google",
"providerId": "google_user_id_123",
"verified": true
}
}Complete Implementation
React OAuth Component
typescript
import { useEffect, useState } from 'react'
function OAuthLogin() {
const [loading, setLoading] = useState(false)
const [error, setError] = useState('')
// Handle OAuth callback
useEffect(() => {
const handleCallback = async () => {
const urlParams = new URLSearchParams(window.location.search)
const code = urlParams.get('code')
const provider = urlParams.get('provider')
if (code && provider) {
setLoading(true)
try {
const response = await fetch(
`https://auth.dedot.io/v1/auth/oauth/${provider}/callback`,
{
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
code,
redirectUri: window.location.origin + '/auth/callback'
})
}
)
const data = await response.json()
if (data.success) {
// Store tokens
localStorage.setItem('accessToken', data.accessToken)
localStorage.setItem('refreshToken', data.refreshToken)
// Redirect to app
window.location.href = '/dashboard'
} else {
setError(data.message || 'OAuth authentication failed')
}
} catch (err) {
setError('Network error. Please try again.')
} finally {
setLoading(false)
}
}
}
handleCallback()
}, [])
const initiateOAuth = (provider: 'google' | 'github' | 'microsoft' | 'apple') => {
const redirectUri = encodeURIComponent(
window.location.origin + '/auth/callback'
)
window.location.href = `https://auth.dedot.io/v1/auth/oauth/${provider}/authorize?redirect_uri=${redirectUri}`
}
if (loading) {
return <div>Authenticating...</div>
}
return (
<div className="oauth-buttons">
<button onClick={() => initiateOAuth('google')}>
<img src="/google-icon.svg" alt="Google" />
Continue with Google
</button>
<button onClick={() => initiateOAuth('github')}>
<img src="/github-icon.svg" alt="GitHub" />
Continue with GitHub
</button>
<button onClick={() => initiateOAuth('microsoft')}>
<img src="/microsoft-icon.svg" alt="Microsoft" />
Continue with Microsoft
</button>
<button onClick={() => initiateOAuth('apple')}>
<img src="/apple-icon.svg" alt="Apple" />
Continue with Apple
</button>
{error && <div className="error">{error}</div>}
</div>
)
}Next.js OAuth Implementation
typescript
// app/auth/[provider]/route.ts
import { NextResponse } from 'next/server'
export async function GET(
request: Request,
{ params }: { params: { provider: string } }
) {
const { searchParams } = new URL(request.url)
const redirectUri = searchParams.get('redirect_uri') ||
`${process.env.NEXT_PUBLIC_APP_URL}/auth/callback`
const authUrl = `https://auth.dedot.io/v1/auth/oauth/${params.provider}/authorize?redirect_uri=${encodeURIComponent(redirectUri)}`
return NextResponse.redirect(authUrl)
}
// app/auth/callback/page.tsx
'use client'
import { useEffect, useState } from 'react'
import { useSearchParams, useRouter } from 'next/navigation'
export default function OAuthCallback() {
const searchParams = useSearchParams()
const router = useRouter()
const [error, setError] = useState('')
useEffect(() => {
const handleCallback = async () => {
const code = searchParams.get('code')
const provider = searchParams.get('provider')
if (!code || !provider) {
setError('Invalid OAuth callback')
return
}
try {
const response = await fetch(
`https://auth.dedot.io/v1/auth/oauth/${provider}/callback`,
{
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
code,
redirectUri: window.location.origin + '/auth/callback'
})
}
)
const data = await response.json()
if (data.success) {
// Store tokens in httpOnly cookies
document.cookie = `accessToken=${data.accessToken}; path=/; secure; samesite=strict`
router.push('/dashboard')
} else {
setError(data.message || 'Authentication failed')
}
} catch (err) {
setError('Network error')
}
}
handleCallback()
}, [searchParams, router])
if (error) {
return <div>Error: {error}</div>
}
return <div>Completing authentication...</div>
}Provider Configuration
Google OAuth
Setup:
- Create OAuth 2.0 Client in Google Cloud Console
- Add authorized redirect URI:
https://auth.dedot.io/v1/auth/oauth/google/callback - Configure in De. dashboard with Client ID and Secret
Scopes Requested:
openidemailprofile
GitHub OAuth
Setup:
- Create OAuth App in GitHub Settings
- Set authorization callback URL:
https://auth.dedot.io/v1/auth/oauth/github/callback - Configure in De. dashboard
Scopes Requested:
user:emailread:user
Microsoft OAuth
Setup:
- Register app in Azure Portal
- Add redirect URI:
https://auth.dedot.io/v1/auth/oauth/microsoft/callback - Configure in De. dashboard
Scopes Requested:
openidemailprofile
Apple Sign In
Setup:
- Configure in Apple Developer Portal
- Add return URL:
https://auth.dedot.io/v1/auth/oauth/apple/callback - Configure in De. dashboard
Scopes Requested:
emailname
Account Linking
Link OAuth provider to existing account:
typescript
POST https://auth.dedot.io/v1/auth/oauth/link
Headers:
Authorization: Bearer <access_token>
Body:
{
"provider": "google",
"code": "AUTH_CODE",
"redirectUri": "https://yourapp.com/auth/callback"
}Response:
json
{
"success": true,
"message": "Google account linked successfully",
"linkedProviders": ["email", "google"]
}Unlink Provider
typescript
DELETE https://auth.dedot.io/v1/auth/oauth/unlink/{provider}
Headers:
Authorization: Bearer <access_token>Response:
json
{
"success": true,
"message": "GitHub account unlinked",
"remainingProviders": ["email", "google"]
}Security Considerations
Best Practices
- Always use state parameter to prevent CSRF
- Validate redirect_uri matches registered URIs
- Store tokens securely (httpOnly cookies)
- Implement PKCE for mobile apps
- Use short-lived authorization codes
- Verify email from OAuth provider
Important Notes
- OAuth tokens are provider-specific
- Email may not be verified by provider
- Not all providers return email
- Handle provider API rate limits
- Implement fallback authentication
- Test with multiple providers
Error Handling
typescript
async function handleOAuthCallback(code: string, provider: string) {
try {
const response = await fetch(
`https://auth.dedot.io/v1/auth/oauth/${provider}/callback`,
{
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
code,
redirectUri: window.location.origin + '/auth/callback'
})
}
)
const data = await response.json()
if (!response.ok) {
switch (response.status) {
case 400:
throw new Error('Invalid authorization code')
case 401:
throw new Error('Provider authentication failed')
case 409:
throw new Error('Account already exists with different provider')
case 429:
throw new Error('Too many requests. Please try again later.')
default:
throw new Error(data.message || 'OAuth authentication failed')
}
}
return data
} catch (error) {
console.error('OAuth error:', error)
throw error
}
}Testing
Development OAuth test accounts:
| Provider | Behavior | |
|---|---|---|
| [email protected] | Always succeeds | |
| github | [email protected] | Always succeeds |
| microsoft | [email protected] | Always succeeds |
Development Only
Test OAuth accounts only work in development environment.

