Skip to content

authentication

Francisco Dias edited this page Aug 18, 2026 · 4 revisions

Authentication & Cookies

Auth schemes

The generator reads components.securitySchemes from the spec and generates one case arm per scheme inside the _apply_auth function on GmRequest. Each endpoint declares which schemes it requires via the generated __security__ array.

Supported scheme types

OpenAPI type What gets injected
http / basic Authorization: Simple <base64(token)>
http / bearer Authorization: Bearer <token>
apiKey / header <key-name>: <token> in the request header
apiKey / query <key-name>=<token> appended to query params
apiKey / cookie <key-name>=<token> appended to the Cookie header
oauth2 Token stored and injected as Bearer; scopes logged; no flow scaffolding
openIdConnect Stored as-is; no OIDC discovery

Schemes that cannot be mapped (e.g. unsupported types) are skipped silently.

Token storage

Tokens live in auth_tokens = {} on obj_gm_core. The scheme name from the spec is the key.

// Store a token (call this after login / token refresh)
gm_request_auth_set_token("bearer_auth", "eyJhbGci...");

// Retrieve (private — used internally; handy when debugging)
var _tok = _gm_request_auth_get_token("bearer_auth");

// API key in a header
gm_request_auth_set_token("api_key", "sk-abc123");

The scheme name "bearer_auth" must match the key in components.securitySchemes of the original spec.

Per-endpoint security

Each generated endpoint wrapper passes a __security__ array to _gm_create_request:

// Endpoint that requires one scheme
var __security__ = ["bearer_auth"];

// Endpoint that accepts multiple schemes (all are injected)
var __security__ = ["api_key", "bearer_auth"];

// Endpoint with no auth (no __security__ declared)
return _gm_create_request(..., undefined, ...);

When a required token is missing, _apply_auth logs a debug message and skips that scheme — no error is thrown, so the request still fires (likely resulting in a 401).

Operation-level security override

If an operation in the spec sets security: [] (empty array), that endpoint explicitly declares no auth and __security__ is not emitted. If security is omitted on the operation, the document-level security is used.


Cookie jar

The cookie jar is a shared struct cookie_jar = {} on the singleton. It is populated automatically and injected into every request.

Auto-capture

After every HTTP response, the controller checks for a Set-Cookie header. GMRT comma-joins multiple Set-Cookie values (RFC 2616 duplicate-header rule), so the capture helper splits on ",", strips attributes (; Path=…, ; Expires=…, etc.), and stores name → value:

Set-Cookie: session=abc123; Path=/; HttpOnly, csrf=xyz; Path=/
→ cookie_jar[$ "session"] = "abc123"
→ cookie_jar[$ "csrf"]    = "xyz"

This happens in _gm_cookie_capture() inside controller_http.gml before any response hook or callback fires, so hooks can already read the jar.

Auto-injection

On every GmRequest.send(), jar entries are written to the Cookie header first, then any per-request explicit cookie parameters from the endpoint signature are appended. Per-request cookies shadow same-named jar entries.

// jar:  session=abc123; csrf=xyz
// per-request override (hand-built GmRequest only): session_id = "override"
// resulting header:
Cookie: session=abc123; csrf=xyz; session_id=override

Public API

gm_cookie_set(_name, _value)    // write or overwrite a cookie manually
gm_cookie_get(_name)            // read; returns undefined if absent
gm_cookie_delete(_name)         // remove one entry
gm_cookie_clear()               // wipe the entire jar

Use these for login flows that return session tokens via the response body rather than via Set-Cookie headers.

Cookie parameters in the spec

An in: cookie parameter is deliberately not exposed as a function argument. The jar already captures and injects cookies automatically, so an argument for one would be misleading — generated endpoints always pass undefined for the per-request cookie slot.

Manage those values with the public API instead:

gm_cookie_set("session_id", "abc123");   // then call the endpoint normally

The per-request slot exists on GmRequest for code that constructs a request by hand; it is not reachable through the generated wrappers.


Response hooks

Response hooks let you intercept HTTP responses globally (by status code) before the per-request callback runs.

// Auto-retry on 401 with a refreshed token
gm_request_response_set_hook(401, function(_code, _data, _request) {
    _refresh_token(function() {
        _request.retry();
    });
    return true;   // return true to suppress the original callback
});

// Log every 500
gm_request_response_set_hook(500, function(_code, _data, _request) {
    show_debug_message($"Server error: {json_stringify(_data)}");
    // return nothing (or false) → callback still fires
});

A hook that returns true stops propagation: the per-request callback is not called and the request is removed from the active map.

Clone this wiki locally