Authentication
Learn how to authenticate users and manage access tokens in your De. application.
Authentication Overview
De. provides multiple authentication methods to suit different use cases:
- Phone number authentication with SMS verification
- Email/password authentication
- OAuth integration (Google, Apple, etc.)
- API key authentication for server-to-server
Authentication Flow
Phone Authentication
Phone authentication is the most common method for end-user apps.
Initiate Authentication
Send phone number to request verification code
import De from '@de./sdk'
const access = new De.Access({
workspace: 'your-workspace-id',
env: 'prod'
})
// Request verification code
const response = await access.request({
url: '/auth/signin',
method: 'POST',
body: {
phone: '+1234567890',
type: 'phone'
}
})
console.log('Verification code sent!')Verify Code
Submit the verification code received via SMS
const authResult = await access.request({
url: '/auth/verify',
method: 'POST',
body: {
phone: '+1234567890',
code: '123456' // Code from SMS
}
})
// Store the access token
const accessToken = authResult.data.token
localStorage.setItem('de_access_token', accessToken)
console.log('User authenticated:', authResult.data.user)Use Access Token
Include token in subsequent requests
// Initialize with access token
const authenticatedAccess = new De.Access({
workspace: 'your-workspace-id',
accessToken: accessToken,
env: 'prod'
})
// Now you can make authenticated requests
const userProfile = await authenticatedAccess.request({
url: '/user',
method: 'GET'
})
console.log('User profile:', userProfile.data)Complete Phone Auth Example
React Example:
import { useState } from 'react'
import De from '@de./sdk'
export function PhoneAuth() {
const [phone, setPhone] = useState('')
const [code, setCode] = useState('')
const [step, setStep] = useState<'phone' | 'code'>('phone')
const [user, setUser] = useState(null)
const access = new De.Access({
workspace: process.env.REACT_APP_WORKSPACE_ID!,
env: 'prod'
})
const requestCode = async () => {
await access.request({
url: '/auth/signin',
method: 'POST',
body: { phone, type: 'phone' }
})
setStep('code')
}
const verifyCode = async () => {
const result = await access.request({
url: '/auth/verify',
method: 'POST',
body: { phone, code }
})
localStorage.setItem('de_access_token', result.data.token)
setUser(result.data.user)
}
if (user) {
return <div>Welcome, {user.profile.firstName}!</div>
}
if (step === 'phone') {
return (
<div>
<input
type="tel"
value={phone}
onChange={(e) => setPhone(e.target.value)}
placeholder="+1234567890"
/>
<button onClick={requestCode}>Send Code</button>
</div>
)
}
return (
<div>
<input
type="text"
value={code}
onChange={(e) => setCode(e.target.value)}
placeholder="Enter 6-digit code"
/>
<button onClick={verifyCode}>Verify</button>
</div>
)
}Vue Example:
<script setup lang="ts">
import { ref } from 'vue'
import De from '@de./sdk'
const phone = ref('')
const code = ref('')
const step = ref<'phone' | 'code'>('phone')
const user = ref(null)
const access = new De.Access({
workspace: import.meta.env.VITE_WORKSPACE_ID,
env: 'prod'
})
const requestCode = async () => {
await access.request({
url: '/auth/signin',
method: 'POST',
body: { phone: phone.value, type: 'phone' }
})
step.value = 'code'
}
const verifyCode = async () => {
const result = await access.request({
url: '/auth/verify',
method: 'POST',
body: { phone: phone.value, code: code.value }
})
localStorage.setItem('de_access_token', result.data.token)
user.value = result.data.user
}
</script>
<template>
<div v-if="user">
Welcome, {{ user.profile.firstName }}!
</div>
<div v-else-if="step === 'phone'">
<input v-model="phone" type="tel" placeholder="+1234567890" />
<button @click="requestCode">Send Code</button>
</div>
<div v-else>
<input v-model="code" type="text" placeholder="Enter 6-digit code" />
<button @click="verifyCode">Verify</button>
</div>
</template>Vanilla JavaScript Example:
import De from '@de./sdk'
const access = new De.Access({
workspace: 'your-workspace-id',
env: 'prod'
})
let phone = ''
let code = ''
// Request verification code
document.getElementById('send-code-btn').addEventListener('click', async () => {
phone = document.getElementById('phone-input').value
await access.request({
url: '/auth/signin',
method: 'POST',
body: { phone, type: 'phone' }
})
// Show code input
document.getElementById('phone-step').style.display = 'none'
document.getElementById('code-step').style.display = 'block'
})
// Verify code
document.getElementById('verify-btn').addEventListener('click', async () => {
code = document.getElementById('code-input').value
const result = await access.request({
url: '/auth/verify',
method: 'POST',
body: { phone, code }
})
localStorage.setItem('de_access_token', result.data.token)
// Show authenticated UI
document.getElementById('user-name').textContent = result.data.user.profile.firstName
document.getElementById('auth-steps').style.display = 'none'
document.getElementById('authenticated').style.display = 'block'
})Email/Password Authentication
For traditional email-based authentication.
Create Account
Register a new user with email and password
const createAccount = await access.request({
url: '/auth/create',
method: 'POST',
body: {
email: '[email protected]',
password: 'SecurePassword123!',
profile: {
firstName: 'John',
lastName: 'Doe'
}
}
})
console.log('Account created:', createAccount.data.user)Sign In
Authenticate with email and password
const signIn = await access.request({
url: '/auth/signin',
method: 'POST',
body: {
email: '[email protected]',
password: 'SecurePassword123!',
type: 'email'
}
})
const accessToken = signIn.data.token
localStorage.setItem('de_access_token', accessToken)Password Requirements
Passwords must meet the following criteria:
- Minimum 8 characters
- At least one uppercase letter
- At least one lowercase letter
- At least one number
- At least one special character
OAuth Authentication
Integrate with third-party OAuth providers.
Google OAuth
Sign in with Google for seamless authentication
Apple Sign In
Enable Apple Sign In for iOS users
Configure OAuth Provider
Set up OAuth credentials in your workspace
Navigate to your workspace dashboard and add OAuth credentials:
{
"provider": "google",
"clientId": "your-google-client-id",
"clientSecret": "your-google-client-secret",
"redirectUri": "https://yourapp.com/auth/callback"
}Initiate OAuth Flow
Redirect user to OAuth provider
// Generate OAuth URL
const oauthUrl = `https://accounts.google.com/o/oauth2/v2/auth?` +
`client_id=${clientId}&` +
`redirect_uri=${redirectUri}&` +
`response_type=code&` +
`scope=openid email profile`
// Redirect user
window.location.href = oauthUrlHandle OAuth Callback
Exchange authorization code for access token
// In your callback handler
const urlParams = new URLSearchParams(window.location.search)
const authCode = urlParams.get('code')
const result = await access.request({
url: '/auth/oauth/callback',
method: 'POST',
body: {
provider: 'google',
code: authCode
}
})
localStorage.setItem('de_access_token', result.data.token)
console.log('OAuth authentication successful:', result.data.user)API Key Authentication
For server-to-server communication.
Use Cases for API Keys
API keys are ideal for:
- Backend services
- Scheduled jobs and cron tasks
- Server-side integrations
- Webhook handlers
Never use API keys in client-side code!
Generate API Key
Create an API key in your workspace dashboard
// Via API (requires admin access)
const apiKey = await access.request({
url: '/workspace/api-keys',
method: 'POST',
body: {
name: 'Production Server',
scopes: ['orders:read', 'orders:write', 'fleet:read'],
expiresAt: '2025-12-31'
}
})
console.log('API Key:', apiKey.data.key)
// Store this securely - it won't be shown again!Use API Key
Authenticate server requests with API key
// Server-side code
import De from '@de./sdk'
const serverAccess = new De.Access({
workspace: process.env.DE_WORKSPACE_ID,
accessToken: process.env.DE_API_KEY, // API key from environment
env: 'prod'
})
// Make authenticated requests
const orders = await serverAccess.request({
url: '/orders',
method: 'GET',
query: { status: 'pending' }
})Token Management
Token Storage
Securely store access tokens in localStorage or cookies
Token Refresh
Automatically refresh tokens before expiration
Token Revocation
Revoke tokens when user signs out
Secure Token Storage
Store Tokens Securely
Best practices for token storage
// Web: Use httpOnly cookies for maximum security
document.cookie = `de_token=${accessToken}; Secure; HttpOnly; SameSite=Strict`
// Or localStorage for client-side access
localStorage.setItem('de_access_token', accessToken)
// Mobile: Use secure storage
import * as SecureStore from 'expo-secure-store'
await SecureStore.setItemAsync('de_access_token', accessToken)Token Refresh
Implement Token Refresh
Refresh tokens before they expire
class TokenManager {
private accessToken: string
private refreshToken: string
private expiresAt: number
async refreshIfNeeded() {
const now = Date.now()
const expiresIn = this.expiresAt - now
// Refresh if token expires in less than 5 minutes
if (expiresIn < 5 * 60 * 1000) {
await this.refresh()
}
}
private async refresh() {
const access = new De.Access({
workspace: 'your-workspace-id',
env: 'prod'
})
const result = await access.request({
url: '/auth/refresh',
method: 'POST',
body: { refreshToken: this.refreshToken }
})
this.accessToken = result.data.token
this.expiresAt = result.data.expiresAt
localStorage.setItem('de_access_token', this.accessToken)
}
}Sign Out
Implement Sign Out
Revoke tokens and clear session
async function signOut() {
const access = new De.Access({
workspace: 'your-workspace-id',
accessToken: localStorage.getItem('de_access_token'),
env: 'prod'
})
// Revoke token on server
await access.request({
url: '/auth/signout',
method: 'POST'
})
// Clear local storage
localStorage.removeItem('de_access_token')
localStorage.removeItem('de_user')
// Redirect to login
window.location.href = '/login'
}User Profile Management
Once authenticated, you can manage user profiles.
Get User Profile
Fetch current user information
const profile = await access.request({
url: '/user',
method: 'GET'
})
console.log('User:', profile.data)
// {
// uid: 'user_123',
// profile: {
// firstName: 'John',
// lastName: 'Doe',
// phone: '+1234567890',
// email: '[email protected]',
// photo: 'https://cdn.dedot.io/avatars/...'
// },
// account: {
// types: ['customer'],
// workspace: 'ws_abc'
// }
// }Update Profile
Modify user information
const updated = await access.request({
url: '/user/profile',
method: 'PATCH',
body: {
profile: {
firstName: 'Jane',
lastName: 'Smith'
}
}
})
console.log('Profile updated:', updated.data)Upload Avatar
Update user profile photo
const formData = new FormData()
formData.append('file', avatarFile)
const upload = await access.request({
url: '/utilities/upload',
method: 'POST',
body: formData,
headers: {
'Content-Type': 'multipart/form-data'
}
})
console.log('Avatar uploaded:', upload.data.url)Role-Based Access Control
De. supports role-based permissions for fine-grained access control.
Check User Permissions
// Check if user has specific permission
const hasPermission = await access.request({
url: '/workspace/access/check',
method: 'POST',
body: {
permission: 'orders:write'
}
})
if (hasPermission.data.allowed) {
// User can create/update orders
}Security Best Practices
Never Expose Credentials
- Don't commit tokens to version control
- Don't log tokens in console or errors
- Don't send tokens in URL parameters
- Use environment variables
Token Expiration
- Set reasonable expiration times
- Implement token refresh logic
- Handle expired tokens gracefully
- Clear tokens on sign out
HTTPS Only
- Always use HTTPS in production
- Enable secure cookie flags
- Implement CORS properly
- Use Content Security Policy
Multi-Factor Auth
- Enable 2FA for sensitive operations
- Use biometric authentication on mobile
- Implement device verification
- Monitor suspicious login attempts
Error Handling
Handle Authentication Errors
Properly handle and display auth errors
async function authenticate(phone: string, code: string) {
try {
const result = await access.request({
url: '/auth/verify',
method: 'POST',
body: { phone, code }
})
return { success: true, data: result.data }
} catch (error) {
if (error.status === 401) {
return { success: false, error: 'Invalid verification code' }
} else if (error.status === 429) {
return { success: false, error: 'Too many attempts. Try again later.' }
} else if (error.status === 400) {
return { success: false, error: 'Invalid phone number format' }
}
return { success: false, error: 'Authentication failed. Please try again.' }
}
}
