mirror of
https://github.com/sol1/rustguac.git
synced 2026-09-11 01:55:38 +00:00
feat(client): accept a ws-ticket in the client URL for headless owner connections
The built-in client could only authenticate the owner WebSocket via an OIDC
session cookie or a sessionStorage API key. Headless API integrations have
neither, so the owner connection was rejected and guacd reported 'User is not
responding'. Now /client/{id}?ticket=<wst> is honoured: a backend mints a
single-use ticket via POST /api/ws-ticket and hands the browser a ready URL,
keeping the durable API key server-side. The metadata fetch is skipped in this
path (it needs its own auth and would consume the one-shot ticket).
This commit is contained in:
+19
-1
@@ -255,6 +255,11 @@
|
||||
var urlParams = new URLSearchParams(window.location.search);
|
||||
var shareToken = urlParams.get('token');
|
||||
var apiKey = sessionStorage.getItem('rustguac_api_key');
|
||||
// Pre-minted single-use WebSocket ticket passed in the URL. Lets a
|
||||
// headless API integration authenticate the owner connection without an
|
||||
// OIDC session or a stored API key: the backend mints it via
|
||||
// POST /api/ws-ticket and hands the browser /client/{id}?ticket=...
|
||||
var urlTicket = urlParams.get('ticket');
|
||||
var entryName = urlParams.get('name');
|
||||
// Populated from /api/sessions/:id when the session is backed by a
|
||||
// Connections entry. Used by the Reconnect button to launch a fresh
|
||||
@@ -311,7 +316,13 @@
|
||||
});
|
||||
}
|
||||
|
||||
if (shareToken) {
|
||||
if (urlTicket) {
|
||||
// Headless API integration: the pre-minted ticket authenticates the
|
||||
// WebSocket directly. Skip the /api/sessions metadata fetch — it
|
||||
// needs its own auth, and routing the one-shot ticket through it
|
||||
// would consume it before the WebSocket. Connect straight away.
|
||||
startGuacamole();
|
||||
} else if (shareToken) {
|
||||
fetch('/api/sessions/' + sessionId + '/banner?token=' + encodeURIComponent(shareToken))
|
||||
.then(function(res) { return res.ok ? res.json() : null; })
|
||||
.then(function(data) { return showBanner(data && data.banner); })
|
||||
@@ -357,6 +368,13 @@
|
||||
function startGuacamole() {
|
||||
statusEl.textContent = 'Connecting to session ' + sessionId.substring(0, 8) + '...';
|
||||
|
||||
// Pre-minted WebSocket ticket from the URL (headless API integration)
|
||||
// takes priority: use it directly as the owner credential.
|
||||
if (urlTicket) {
|
||||
connectWebSocket(urlTicket);
|
||||
return;
|
||||
}
|
||||
|
||||
// API key users: exchange key for a single-use ticket before connecting.
|
||||
// This keeps the API key out of the WebSocket URL (visible in logs).
|
||||
if (apiKey) {
|
||||
|
||||
Reference in New Issue
Block a user