283 lines
11 KiB
PHP
283 lines
11 KiB
PHP
<?php return [
|
|
'render' => function($prop) {
|
|
$services = $prop['services'] ?? [
|
|
'google' => [
|
|
'name' => 'Google',
|
|
'color' => '#4285f4',
|
|
'icon' => 'fab fa-google',
|
|
'scope' => 'openid email profile',
|
|
'auth_url' => 'https://accounts.google.com/oauth/authorize',
|
|
'token_url' => 'https://oauth2.googleapis.com/token',
|
|
'user_info_url' => 'https://www.googleapis.com/oauth2/v2/userinfo'
|
|
],
|
|
'github' => [
|
|
'name' => 'GitHub',
|
|
'color' => '#333333',
|
|
'icon' => 'fab fa-github',
|
|
'scope' => 'user:email',
|
|
'auth_url' => 'https://github.com/login/oauth/authorize',
|
|
'token_url' => 'https://github.com/login/oauth/access_token',
|
|
'user_info_url' => 'https://api.github.com/user'
|
|
],
|
|
'discord' => [
|
|
'name' => 'Discord',
|
|
'color' => '#5865f2',
|
|
'icon' => 'fab fa-discord',
|
|
'scope' => 'identify email',
|
|
'auth_url' => 'https://discord.com/api/oauth2/authorize',
|
|
'token_url' => 'https://discord.com/api/oauth2/token',
|
|
'user_info_url' => 'https://discord.com/api/users/@me'
|
|
],
|
|
'twitch' => [
|
|
'name' => 'Twitch',
|
|
'color' => '#9146ff',
|
|
'icon' => 'fab fa-twitch',
|
|
'scope' => 'user:read:email',
|
|
'auth_url' => 'https://id.twitch.tv/oauth2/authorize',
|
|
'token_url' => 'https://id.twitch.tv/oauth2/token',
|
|
'user_info_url' => 'https://api.twitch.tv/helix/users'
|
|
]
|
|
];
|
|
$title = $prop['title'] ?? 'Sign in with OAuth';
|
|
$subtitle = $prop['subtitle'] ?? 'Choose your preferred authentication method';
|
|
$callback_url = $prop['callback_url'] ?? URL::Link('auth/callback');
|
|
|
|
?>
|
|
<form class="card">
|
|
<div>
|
|
<h2><?= safe($title) ?></h2>
|
|
<label><?= safe($subtitle) ?></label>
|
|
</div>
|
|
|
|
<?php foreach($services as $service_key => $service): ?>
|
|
<div data-service="<?= safe($service_key) ?>">
|
|
<button type="button" class="btn" onclick="initiateOAuth('<?= safe($service_key) ?>')">
|
|
<i class="<?= safe($service['icon']) ?>" style="color: <?= safe($service['color']) ?>"></i>
|
|
Continue with <?= safe($service['name']) ?>
|
|
</button>
|
|
|
|
<div class="loading" style="display: none;">
|
|
<span>Connecting...</span>
|
|
</div>
|
|
|
|
<label>Secure authentication via <?= safe($service['name']) ?></label>
|
|
</div>
|
|
<?php endforeach; ?>
|
|
|
|
<div class="banner" id="oauth-status" style="display: none;">
|
|
<div class="status-icon"></div>
|
|
<div class="status-message"></div>
|
|
</div>
|
|
</form>
|
|
|
|
<div class="card" id="oauth-debug" style="display: none;">
|
|
<h4>Debug Information</h4>
|
|
<pre id="oauth-debug-content"></pre>
|
|
</div>
|
|
|
|
<script>
|
|
// OAuth configuration for different services
|
|
const oauthConfig = {
|
|
<?php foreach($services as $service_key => $service): ?>
|
|
<?= $service_key ?>: {
|
|
clientId: '<?= safe($prop[$service_key . '_client_id'] ?? 'YOUR_' . strtoupper($service_key) . '_CLIENT_ID') ?>',
|
|
clientSecret: '<?= safe($prop[$service_key . '_client_secret'] ?? '') ?>', // Only needed for server-side flow
|
|
redirectUri: '<?= safe($callback_url) ?>',
|
|
scope: '<?= safe($service['scope']) ?>',
|
|
authUrl: '<?= safe($service['auth_url']) ?>',
|
|
tokenUrl: '<?= safe($service['token_url']) ?>',
|
|
userInfoUrl: '<?= safe($service['user_info_url']) ?>',
|
|
additionalParams: {
|
|
<?php
|
|
// Add service-specific parameters
|
|
switch ($service_key) {
|
|
case 'google':
|
|
echo "'access_type': 'offline', 'prompt': 'select_account'";
|
|
break;
|
|
case 'discord':
|
|
echo "'prompt': 'consent'";
|
|
break;
|
|
case 'github':
|
|
echo "'allow_signup': 'true'";
|
|
break;
|
|
case 'twitch':
|
|
echo "'force_verify': 'true'";
|
|
break;
|
|
}
|
|
?>
|
|
}
|
|
},
|
|
<?php endforeach; ?>
|
|
};
|
|
|
|
// Global OAuth functions
|
|
window.initiateOAuth = function(service) {
|
|
const $serviceDiv = $(`[data-service="${service}"]`);
|
|
const $button = $serviceDiv.find('.btn');
|
|
const $loading = $serviceDiv.find('.loading');
|
|
const $status = $('#oauth-status');
|
|
const $debug = $('#oauth-debug');
|
|
|
|
// Show loading state
|
|
$button.hide();
|
|
$loading.show();
|
|
|
|
// Hide previous status/debug info
|
|
$status.hide();
|
|
$debug.hide();
|
|
|
|
if (oauthConfig[service]) {
|
|
initiateOAuthFlow(service);
|
|
} else {
|
|
showError('Unsupported OAuth service: ' + service);
|
|
resetButton(service);
|
|
}
|
|
|
|
function resetButton(service) {
|
|
setTimeout(() => {
|
|
$(`[data-service="${service}"] .btn`).show();
|
|
$(`[data-service="${service}"] .loading`).hide();
|
|
}, 1000);
|
|
}
|
|
};
|
|
|
|
function initiateOAuthFlow(service) {
|
|
const config = oauthConfig[service];
|
|
|
|
if (config.clientId.includes('YOUR_')) {
|
|
showError(`${service.charAt(0).toUpperCase() + service.slice(1)} OAuth not configured. Please set ${service}_client_id in the component properties.`);
|
|
$(`[data-service="${service}"] .btn`).show();
|
|
$(`[data-service="${service}"] .loading`).hide();
|
|
return;
|
|
}
|
|
|
|
// Build OAuth URL
|
|
const params = new URLSearchParams({
|
|
client_id: config.clientId,
|
|
redirect_uri: config.redirectUri,
|
|
scope: config.scope,
|
|
response_type: 'code',
|
|
state: generateState()
|
|
});
|
|
|
|
// Add service-specific parameters
|
|
for (const [key, value] of Object.entries(config.additionalParams || {})) {
|
|
params.set(key, value);
|
|
}
|
|
|
|
const authUrl = `${config.authUrl}?${params.toString()}`;
|
|
|
|
// Store state in session storage for verification
|
|
sessionStorage.setItem('oauth_state', params.get('state'));
|
|
sessionStorage.setItem('oauth_service', service);
|
|
|
|
// Also store in PHP session for callback handler
|
|
<?php if (session_status() === PHP_SESSION_ACTIVE): ?>
|
|
$.post('<?= URL::Link('auth/store-oauth-session') ?>', {
|
|
oauth_service: service,
|
|
oauth_state: params.get('state')
|
|
}).catch(console.error);
|
|
<?php endif; ?>
|
|
|
|
// Debug information
|
|
showDebug({
|
|
service: service,
|
|
authUrl: authUrl,
|
|
clientId: config.clientId,
|
|
redirectUri: config.redirectUri,
|
|
scope: config.scope,
|
|
state: params.get('state')
|
|
});
|
|
|
|
// Redirect to OAuth provider
|
|
window.location.href = authUrl;
|
|
}
|
|
|
|
function generateState() {
|
|
return btoa(Math.random().toString(36).substring(2, 15) +
|
|
Math.random().toString(36).substring(2, 15)).replace(/[^a-zA-Z0-9]/g, '');
|
|
}
|
|
|
|
function showStatus(message, type = 'loading') {
|
|
const $status = $('#oauth-status');
|
|
const $icon = $status.find('.status-icon');
|
|
const $message = $status.find('.status-message');
|
|
|
|
$status.removeClass('success error loading').addClass(type).show();
|
|
|
|
let icon = '';
|
|
switch(type) {
|
|
case 'success': icon = '✓'; break;
|
|
case 'error': icon = '✗'; break;
|
|
case 'loading': icon = '⏳'; break;
|
|
}
|
|
|
|
$icon.text(icon);
|
|
$message.text(message);
|
|
}
|
|
|
|
function showError(message) {
|
|
showStatus(message, 'error');
|
|
}
|
|
|
|
function showSuccess(message) {
|
|
showStatus(message, 'success');
|
|
}
|
|
|
|
function showDebug(data) {
|
|
$('#oauth-debug-content').text(JSON.stringify(data, null, 2));
|
|
$('#oauth-debug').show();
|
|
}
|
|
|
|
// Check for OAuth callback parameters on page load
|
|
$.ready(function() {
|
|
const urlParams = new URLSearchParams(window.location.search);
|
|
const code = urlParams.get('code');
|
|
const state = urlParams.get('state');
|
|
const error = urlParams.get('error');
|
|
|
|
if (error) {
|
|
showError('OAuth failed: ' + (urlParams.get('error_description') || error));
|
|
return;
|
|
}
|
|
|
|
if (code && state) {
|
|
const storedState = sessionStorage.getItem('oauth_state');
|
|
const service = sessionStorage.getItem('oauth_service');
|
|
|
|
if (state !== storedState) {
|
|
showError('Invalid OAuth state. Possible security issue.');
|
|
return;
|
|
}
|
|
|
|
showStatus('Authorization successful! Processing...', 'success');
|
|
|
|
showDebug({
|
|
step: 'callback_received',
|
|
service: service,
|
|
code: code.substring(0, 20) + '...',
|
|
state: state,
|
|
next_steps: [
|
|
'Send code to backend OAuth handler',
|
|
'Exchange code for access token',
|
|
'Get user profile from OAuth provider',
|
|
'Create or login user account',
|
|
'Set session and redirect to dashboard'
|
|
]
|
|
});
|
|
|
|
// Clean up session storage
|
|
sessionStorage.removeItem('oauth_state');
|
|
sessionStorage.removeItem('oauth_service');
|
|
|
|
// Remove OAuth parameters from URL for cleaner display
|
|
const cleanUrl = window.location.pathname;
|
|
window.history.replaceState({}, document.title, cleanUrl);
|
|
}
|
|
});
|
|
</script>
|
|
<?php
|
|
},
|
|
|
|
'about' => 'OAuth authentication component with support for Google and other providers. Handles the complete OAuth flow including state verification and callback processing.'
|
|
];
|