FeaturesTemplatesShowcaseTownie
AI
BlogDocsPricing
Log inSign up
c15r

c15r

GHauth

Public
Like
1
GHauth
Home
Code
5
backend
1
examples
1
frontend
1
shared
1
README.md
Branches
1
Pull requests
Remixes
History
Environment variables
3
Val Town is a collaborative website to build and scale JavaScript apps.
Deploy APIs, crons, & store data – all from the browser, and deployed in milliseconds.
Sign up now
Code
/
examples
/
client-integration.md
Code
/
examples
/
client-integration.md
Search
5/27/2025
Viewing readonly version of main branch: v14
View latest version
client-integration.md

Client Integration Examples

JavaScript/TypeScript Integration

1. Redirect to Auth Service

// Redirect user to GitHub auth service function signInWithGitHub() { const authServiceUrl = 'https://your-auth-service.web.val.run'; const redirectUri = encodeURIComponent(window.location.origin + '/auth-callback'); window.location.href = `${authServiceUrl}/auth/signin?redirect_uri=${redirectUri}`; }

2. Handle Auth Callback

// Handle the callback with token function handleAuthCallback() { const urlParams = new URLSearchParams(window.location.search); const token = urlParams.get('token'); if (token) { // Store token securely localStorage.setItem('auth_token', token); // Validate token and get user info validateToken(token); // Clean up URL window.history.replaceState({}, document.title, window.location.pathname); } } // Call this on page load window.addEventListener('load', handleAuthCallback);

3. Validate Token and Get User Info

async function validateToken(token) { const authServiceUrl = 'https://your-auth-service.web.val.run'; try { const response = await fetch(`${authServiceUrl}/auth/validate?token=${token}`); const data = await response.json(); if (data.valid) { console.log('User:', data.user); // Update UI with user info updateUserInterface(data.user); } else { console.error('Invalid token:', data.error); // Redirect to sign in signInWithGitHub(); } } catch (error) { console.error('Token validation failed:', error); } }

4. Complete React Example

Create val
import React, { useState, useEffect } from 'react'; const AUTH_SERVICE_URL = 'https://your-auth-service.web.val.run'; function App() { const [user, setUser] = useState(null); const [loading, setLoading] = useState(true); useEffect(() => { // Check for auth callback const urlParams = new URLSearchParams(window.location.search); const token = urlParams.get('token'); if (token) { localStorage.setItem('auth_token', token); window.history.replaceState({}, document.title, window.location.pathname); validateToken(token); } else { // Check for existing token const existingToken = localStorage.getItem('auth_token'); if (existingToken) { validateToken(existingToken); } else { setLoading(false); } } }, []); const validateToken = async (token) => { try { const response = await fetch(`${AUTH_SERVICE_URL}/auth/validate?token=${token}`); const data = await response.json(); if (data.valid) { setUser(data.user); } else { localStorage.removeItem('auth_token'); } } catch (error) { console.error('Token validation failed:', error); localStorage.removeItem('auth_token'); } finally { setLoading(false); } }; const signIn = () => { const redirectUri = encodeURIComponent(window.location.origin); window.location.href = `${AUTH_SERVICE_URL}/auth/signin?redirect_uri=${redirectUri}`; }; const signOut = () => { localStorage.removeItem('auth_token'); setUser(null); }; if (loading) { return <div>Loading...</div>; } return ( <div> {user ? ( <div> <h1>Welcome, {user.name || user.login}!</h1> <img src={user.avatar_url} alt="Avatar" width="50" height="50" /> <button onClick={signOut}>Sign Out</button> </div> ) : ( <div> <h1>Please sign in</h1> <button onClick={signIn}>Sign in with GitHub</button> </div> )} </div> ); } export default App;

Backend Integration (Node.js/Express)

const express = require('express'); const fetch = require('node-fetch'); const app = express(); const AUTH_SERVICE_URL = 'https://your-auth-service.web.val.run'; // Middleware to validate auth token async function validateAuth(req, res, next) { const token = req.headers.authorization?.replace('Bearer ', ''); if (!token) { return res.status(401).json({ error: 'No token provided' }); } try { const response = await fetch(`${AUTH_SERVICE_URL}/auth/validate?token=${token}`); const data = await response.json(); if (data.valid) { req.user = data.user; next(); } else { res.status(401).json({ error: 'Invalid token' }); } } catch (error) { res.status(500).json({ error: 'Token validation failed' }); } } // Protected route app.get('/api/profile', validateAuth, (req, res) => { res.json({ user: req.user }); }); app.listen(3000);

Security Best Practices

  1. Token Storage: Store tokens securely (httpOnly cookies for web apps)
  2. Token Validation: Always validate tokens on the server side for protected routes
  3. HTTPS Only: Only use this service over HTTPS in production
  4. Token Expiry: Tokens expire after 7 days - implement refresh logic
  5. Environment Variables: Never expose your GitHub client secret

Error Handling

// Handle common errors async function handleAuthError(error) { if (error.message.includes('Invalid token')) { // Token expired or invalid - redirect to sign in localStorage.removeItem('auth_token'); signInWithGitHub(); } else if (error.message.includes('Network')) { // Network error - show retry option showRetryDialog(); } else { // Other errors console.error('Auth error:', error); } }
FeaturesVersion controlCode intelligenceCLI
Use cases
TeamsAI agentsSlackGTM
ExploreDocsShowcaseTemplatesNewestTrendingAPI examplesNPM packages
PricingNewsletterBlogAboutCareersBrandhi@val.townStatus
X (Twitter)
Discord community
GitHub discussions
YouTube channel
Bluesky
Terms of usePrivacy policyAbuse contact
© 2025 Val Town, Inc.