Skip to content

Instantly share code, notes, and snippets.

@ibuilder
Created March 29, 2025 00:04
Show Gist options
  • Save ibuilder/45ac5750e0aea0ae22f076af5207cc12 to your computer and use it in GitHub Desktop.
Save ibuilder/45ac5750e0aea0ae22f076af5207cc12 to your computer and use it in GitHub Desktop.
This HTML page provides a complete interface for interacting with the Procore API using Bootstrap for styling. Here's what it includes: Authentication Section Form to enter your Procore API credentials (Client ID and Secret) Implements OAuth 2.0 authentication flow Stores tokens securely in localStorage API Request Section Dropdown to select com…
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Procore API Integration</title>
<!-- Bootstrap CSS -->
<link href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.3.0/css/bootstrap.min.css" rel="stylesheet">
<style>
.card {
margin-bottom: 20px;
}
#apiResponseContainer {
max-height: 400px;
overflow-y: auto;
}
.loading {
display: none;
}
</style>
</head>
<body>
<div class="container mt-5">
<h1 class="mb-4">Procore API Integration</h1>
<!-- Authentication Card -->
<div class="card">
<div class="card-header bg-primary text-white">
<h5 class="mb-0">Authentication</h5>
</div>
<div class="card-body">
<form id="authForm">
<div class="mb-3">
<label for="clientId" class="form-label">Client ID</label>
<input type="text" class="form-control" id="clientId" required>
</div>
<div class="mb-3">
<label for="clientSecret" class="form-label">Client Secret</label>
<input type="password" class="form-control" id="clientSecret" required>
</div>
<div class="mb-3">
<label for="redirectUri" class="form-label">Redirect URI</label>
<input type="text" class="form-control" id="redirectUri" value="http://localhost:8000/callback" required>
</div>
<button type="submit" class="btn btn-primary">Authenticate</button>
</form>
</div>
</div>
<!-- API Request Card -->
<div class="card">
<div class="card-header bg-success text-white">
<h5 class="mb-0">API Request</h5>
</div>
<div class="card-body">
<form id="apiRequestForm">
<div class="mb-3">
<label for="endpoint" class="form-label">API Endpoint</label>
<select class="form-select" id="endpoint" required>
<option value="">Select an endpoint</option>
<option value="/rest/v1.0/projects">List Projects</option>
<option value="/rest/v1.0/companies">List Companies</option>
<option value="/rest/v1.0/tasks">List Tasks</option>
<option value="/rest/v1.0/users">List Users</option>
<option value="/rest/v1.0/project_tools">List Project Tools</option>
</select>
</div>
<div class="mb-3">
<label for="projectId" class="form-label">Project ID (if applicable)</label>
<input type="text" class="form-control" id="projectId">
</div>
<div class="mb-3">
<label for="method" class="form-label">HTTP Method</label>
<select class="form-select" id="method" required>
<option value="GET">GET</option>
<option value="POST">POST</option>
<option value="PUT">PUT</option>
<option value="DELETE">DELETE</option>
</select>
</div>
<div class="mb-3">
<label for="requestBody" class="form-label">Request Body (JSON, if applicable)</label>
<textarea class="form-control" id="requestBody" rows="3"></textarea>
</div>
<button type="submit" class="btn btn-success" id="sendRequestBtn">Send Request</button>
<div class="spinner-border text-success loading mt-2" id="loadingSpinner" role="status">
<span class="visually-hidden">Loading...</span>
</div>
</form>
</div>
</div>
<!-- API Response Card -->
<div class="card">
<div class="card-header bg-info text-white">
<h5 class="mb-0">API Response</h5>
</div>
<div class="card-body">
<div id="apiResponseContainer" class="bg-light p-3 rounded">
<pre id="apiResponse">No response yet</pre>
</div>
</div>
</div>
</div>
<!-- Bootstrap and other JavaScript libraries -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.3.0/js/bootstrap.bundle.min.js"></script>
<script>
// Global access token variable
let accessToken = '';
const BASE_URL = 'https://api.procore.com';
// Check if we have a token in localStorage
document.addEventListener('DOMContentLoaded', () => {
accessToken = localStorage.getItem('procoreAccessToken');
if (accessToken) {
displayMessage('Found existing access token.');
}
});
// Function to initiate OAuth flow
document.getElementById('authForm').addEventListener('submit', (e) => {
e.preventDefault();
const clientId = document.getElementById('clientId').value;
const redirectUri = document.getElementById('redirectUri').value;
// Store client details for later use
localStorage.setItem('procoreClientId', clientId);
localStorage.setItem('procoreClientSecret', document.getElementById('clientSecret').value);
localStorage.setItem('procoreRedirectUri', redirectUri);
// Redirect to Procore authorization URL
const authUrl = `${BASE_URL}/oauth/authorize?client_id=${clientId}&response_type=code&redirect_uri=${encodeURIComponent(redirectUri)}`;
window.location.href = authUrl;
});
// Function to check for authorization code in URL after redirect
function checkForAuthCode() {
const urlParams = new URLSearchParams(window.location.search);
const code = urlParams.get('code');
if (code) {
// Exchange code for token
exchangeCodeForToken(code);
}
}
// Function to exchange authorization code for access token
async function exchangeCodeForToken(code) {
try {
const clientId = localStorage.getItem('procoreClientId');
const clientSecret = localStorage.getItem('procoreClientSecret');
const redirectUri = localStorage.getItem('procoreRedirectUri');
const response = await fetch(`${BASE_URL}/oauth/token`, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
grant_type: 'authorization_code',
code: code,
client_id: clientId,
client_secret: clientSecret,
redirect_uri: redirectUri
})
});
if (!response.ok) {
throw new Error('Failed to exchange code for token');
}
const data = await response.json();
accessToken = data.access_token;
localStorage.setItem('procoreAccessToken', accessToken);
displayMessage('Successfully authenticated with Procore!');
// Clear the URL to remove the authorization code
window.history.replaceState({}, document.title, window.location.pathname);
} catch (error) {
displayError('Authentication error: ' + error.message);
}
}
// Function to send API requests
document.getElementById('apiRequestForm').addEventListener('submit', async (e) => {
e.preventDefault();
if (!accessToken) {
displayError('You need to authenticate first!');
return;
}
const endpoint = document.getElementById('endpoint').value;
const method = document.getElementById('method').value;
const projectId = document.getElementById('projectId').value;
const requestBody = document.getElementById('requestBody').value;
// Show loading spinner
document.getElementById('loadingSpinner').style.display = 'inline-block';
document.getElementById('sendRequestBtn').disabled = true;
try {
// Determine the URL based on whether a project ID is provided
let url = BASE_URL + endpoint;
if (projectId && endpoint.includes('projects')) {
url = `${BASE_URL}/rest/v1.0/projects/${projectId}` + endpoint.replace('/rest/v1.0/projects', '');
}
const options = {
method: method,
headers: {
'Authorization': `Bearer ${accessToken}`,
'Content-Type': 'application/json'
}
};
// Add request body for POST and PUT requests
if ((method === 'POST' || method === 'PUT') && requestBody) {
options.body = requestBody;
}
const response = await fetch(url, options);
const data = await response.json();
// Display the response
document.getElementById('apiResponse').textContent = JSON.stringify(data, null, 2);
} catch (error) {
displayError('API request error: ' + error.message);
} finally {
// Hide loading spinner
document.getElementById('loadingSpinner').style.display = 'none';
document.getElementById('sendRequestBtn').disabled = false;
}
});
// Helper function to display messages
function displayMessage(message) {
document.getElementById('apiResponse').textContent = message;
}
// Helper function to display errors
function displayError(error) {
document.getElementById('apiResponse').textContent = `ERROR: ${error}`;
document.getElementById('apiResponse').style.color = 'red';
}
// Check for auth code when page loads
checkForAuthCode();
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment