Sofort einsetzbare Beispiele

Schnellstarts (Quickstarts)

Integrieren Sie „Mit Orneos anmelden“ in wenigen Minuten in PHP, Node.js, Python oder einer Single-Page-Anwendung (SPA).

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
<?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
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
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
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);
}