PHP 8.2+ (Vertrauliche Web-Anwendung)
Erzeugt die PKCE-Challenge in der Sitzung, leitet zu login.orneos.eu weiter und tauscht den Code per cURL ein.
login.php & callback.php
Kopieren
<?php
session_start();
$clientId = 'orn_IHRE_CLIENT_ID';
$clientSecret = 'orns_IHR_CLIENT_SECRET';
$redirectUri = 'https://example.com/callback.php';
if (!isset($_GET['code'])) {
$verifier = rtrim(strtr(base64_encode(random_bytes(32)), '+/', '-_'), '=');
$challenge = rtrim(strtr(base64_encode(hash('sha256', $verifier, true)), '+/', '-_'), '=');
$state = bin2hex(random_bytes(16));
$_SESSION['oauth'] = ['verifier' => $verifier, 'state' => $state];
header('Location: https://login.orneos.eu/oauth/authorize?' . http_build_query([
'client_id' => $clientId,
'redirect_uri' => $redirectUri,
'response_type' => 'code',
'scope' => 'openid profile email',
'state' => $state,
'code_challenge' => $challenge,
'code_challenge_method' => 'S256',
]));
exit;
}
if (!hash_equals($_SESSION['oauth']['state'] ?? '', $_GET['state'] ?? '')) {
http_response_code(400);
exit('Invalid state');
}
$ch = curl_init('https://orneos.eu/oauth/token');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_USERPWD => $clientId . ':' . $clientSecret,
CURLOPT_POSTFIELDS => http_build_query([
'grant_type' => 'authorization_code',
'code' => $_GET['code'],
'redirect_uri' => $redirectUri,
'code_verifier' => $_SESSION['oauth']['verifier'],
]),
]);
$tokens = json_decode(curl_exec($ch), true);
Node.js 20+ (Express / Fetch)
Nutzt das integrierte Modul node:crypto für die S256-PKCE-Challenge und fetch für den Token-Austausch.
orneos-auth.mjs
Kopieren
import crypto from 'node:crypto';
export function createPkcePair() {
const verifier = crypto.randomBytes(32).toString('base64url');
const challenge = crypto.createHash('sha256').update(verifier).digest('base64url');
return { verifier, challenge, state: crypto.randomBytes(16).toString('hex') };
}
export async function exchangeCode({ clientId, clientSecret, code, redirectUri, verifier }) {
const res = await fetch('https://orneos.eu/oauth/token', {
method: 'POST',
headers: {
'Authorization': 'Basic ' + Buffer.from(`${clientId}:${clientSecret}`).toString('base64'),
'Content-Type': 'application/x-www-form-urlencoded',
},
body: new URLSearchParams({
grant_type: 'authorization_code',
code,
redirect_uri: redirectUri,
code_verifier: verifier,
}),
});
return res.json();
}
Python 3.11+ (FastAPI / Requests)
Berechnet die PKCE-Challenge mit hashlib und secrets und tauscht anschließend den Code ein.
orneos_oauth.py
Kopieren
import base64, hashlib, secrets, requests
def generate_pkce():
verifier = secrets.token_urlsafe(32)
digest = hashlib.sha256(verifier.encode('ascii')).digest()
challenge = base64.urlsafe_b64encode(digest).rstrip(b'=').decode('ascii')
return verifier, challenge
def exchange_code(client_id: str, client_secret: str, code: str, redirect_uri: str, verifier: str) -> dict:
r = requests.post(
'https://orneos.eu/oauth/token',
auth=(client_id, client_secret),
data={
'grant_type': 'authorization_code',
'code': code,
'redirect_uri': redirect_uri,
'code_verifier': verifier,
},
timeout=10,
)
r.raise_for_status()
return r.json()
SPA / Öffentlicher Client (Browser, ohne Geheimnis)
Wählen Sie in der Konsole den Typ Öffentlicher Client (SPA / Mobil) . Es wird kein client_secret benötigt; der Austausch erfolgt nur mit client_id und code_verifier.
pkce-spa.js
Kopieren
async function startOrneosLogin(clientId, redirectUri) {
const bytes = crypto.getRandomValues(new Uint8Array(32));
const b64 = (buf) => btoa(String.fromCharCode(...new Uint8Array(buf)))
.replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '');
const verifier = b64(bytes);
const challenge = b64(await crypto.subtle.digest('SHA-256', new TextEncoder().encode(verifier)));
const state = b64(crypto.getRandomValues(new Uint8Array(16)));
sessionStorage.setItem('orneos_pkce_verifier', verifier);
sessionStorage.setItem('orneos_oauth_state', state);
const params = new URLSearchParams({
client_id: clientId,
redirect_uri: redirectUri,
response_type: 'code',
scope: 'openid profile email',
state,
code_challenge: challenge,
code_challenge_method: 'S256',
});
window.location.assign('https://login.orneos.eu/oauth/authorize?' + params);
}
Kein Abschnitt entspricht Ihrer Suche.