Add Login with Vanilla JavaScript
This quickstart shows how to integrate Optare with pure JavaScript - no React, Vue, or other frameworks.
Prerequisites
- A web server (or use
npx serve) - An Optare account
1. Get Your Client ID
- Log in to Optare Console (opens in a new tab)
- Create an OAuth client:
- Type: Single Page Application
- Redirect URI:
https://yourapp.com/callback.html
- Copy the Client ID
2. Create Login Page
Create index.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>My App</title>
</head>
<body>
<div id="app">
<button id="login-btn">Log In</button>
<div id="user-info" style="display: none;">
<p>Welcome, <span id="user-name"></span>!</p>
<button id="logout-btn">Log Out</button>
</div>
</div>
<script>
const OPTARE_DOMAIN = 'https://id.optare.one';
const CLIENT_ID = 'your_client_id';
const REDIRECT_URI = 'https://yourapp.com/callback.html';
// Generate PKCE code verifier
function generateCodeVerifier() {
const array = new Uint8Array(32);
crypto.getRandomValues(array);
return btoa(String.fromCharCode(...array))
.replace(/\+/g, '-')
.replace(/\//g, '_')
.replace(/=/g, '');
}
// Generate PKCE code challenge
async function generateCodeChallenge(verifier) {
const encoder = new TextEncoder();
const data = encoder.encode(verifier);
const digest = await crypto.subtle.digest('SHA-256', data);
return btoa(String.fromCharCode(...new Uint8Array(digest)))
.replace(/\+/g, '-')
.replace(/\//g, '_')
.replace(/=/g, '');
}
// Login
document.getElementById('login-btn').onclick = async () => {
const verifier = generateCodeVerifier();
const challenge = await generateCodeChallenge(verifier);
// Store verifier for callback
sessionStorage.setItem('code_verifier', verifier);
const params = new URLSearchParams({
client_id: CLIENT_ID,
redirect_uri: REDIRECT_URI,
response_type: 'code',
scope: 'openid profile email',
code_challenge: challenge,
code_challenge_method: 'S256',
});
window.location.href = `${OPTARE_DOMAIN}/oauth/authorize?${params}`;
};
// Check if logged in
const token = localStorage.getItem('access_token');
if (token) {
document.getElementById('login-btn').style.display = 'none';
document.getElementById('user-info').style.display = 'block';
// Decode token to get email
const payload = JSON.parse(atob(token.split('.')[1]));
document.getElementById('user-name').textContent = payload.email;
}
// Logout
document.getElementById('logout-btn').onclick = () => {
localStorage.removeItem('access_token');
window.location.reload();
};
</script>
</body>
</html>3. Create Callback Page
Create callback.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Logging in...</title>
</head>
<body>
<p>Logging you in...</p>
<script>
const OPTARE_DOMAIN = 'https://id.optare.one';
const CLIENT_ID = 'your_client_id';
const REDIRECT_URI = 'https://yourapp.com/callback.html';
async function handleCallback() {
const params = new URLSearchParams(window.location.search);
const code = params.get('code');
const error = params.get('error');
if (error) {
alert('Login failed: ' + error);
window.location.href = '/';
return;
}
if (!code) {
alert('No authorization code received');
window.location.href = '/';
return;
}
const verifier = sessionStorage.getItem('code_verifier');
sessionStorage.removeItem('code_verifier');
// Exchange code for tokens
const response = await fetch(`${OPTARE_DOMAIN}/oauth/token`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
grant_type: 'authorization_code',
code,
client_id: CLIENT_ID,
redirect_uri: REDIRECT_URI,
code_verifier: verifier,
}),
});
const tokens = await response.json();
if (tokens.error) {
alert('Token exchange failed: ' + tokens.error);
window.location.href = '/';
return;
}
// Store tokens
localStorage.setItem('access_token', tokens.access_token);
if (tokens.refresh_token) {
localStorage.setItem('refresh_token', tokens.refresh_token);
}
// Redirect to app
window.location.href = '/';
}
handleCallback();
</script>
</body>
</html>4. Run the App
npx serve .Open https://yourapp.com (opens in a new tab)!
Security Notes
- This example uses PKCE (Proof Key for Code Exchange) for security
- Tokens are stored in
localStorage- consider using memory storage for higher security - For production, use the SDK instead of raw API calls
Next Steps
- React Quickstart - Use the React SDK
- Tokens Explained - Understand tokens