GHauth
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.
// 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}`;
}
// 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);
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);
}
}
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;
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);
- Token Storage: Store tokens securely (httpOnly cookies for web apps)
- Token Validation: Always validate tokens on the server side for protected routes
- HTTPS Only: Only use this service over HTTPS in production
- Token Expiry: Tokens expire after 7 days - implement refresh logic
- Environment Variables: Never expose your GitHub client secret
// 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);
}
}