Orbito - Dokumentacja modułówOrbito - Dokumentacja modułów
Wprowadzenie
Pierwsze kroki
API
Komunikacja
Widoki
Wdrożenie
Społeczność
For AI agents
Wprowadzenie
Pierwsze kroki
API
Komunikacja
Widoki
Wdrożenie
Społeczność
For AI agents
  • API biblioteki

    • API biblioteki @orbito/api-lib
    • Core
    • Log
    • Utils
    • Pages
    • Automation
    • DB
    • Config
    • Files
    • Problems
    • History
    • OAuth
    • Time
    • Mail
    • Templates
    • Lock
    • Uprawnienia

OAuth

Moduł OAuth pozwala odebrać przekierowanie OAuth od zewnętrznego serwisu (Amazon SP-API, Allegro i inne) bez publicznej strony modułu (od SDK 4.2.0).

const { OAuth } = require('@orbito/api-lib');

OAuth.createTicket({ finishMethod, returnTo, userId, meta?, ttl? })   // -> { state, redirectUri, expiresAt }

Dlaczego callback odbiera rdzeń

Dostawcy OAuth rejestrują adres powrotu (redirect URI) raz, globalnie, dla całej aplikacji autora modułu. Adres nie może więc zależeć od firmy ani od instalacji modułu. Moduł działa w izolowanym kontenerze i nigdy nie serwuje odpowiedzi HTTP, więc ten jeden publiczny adres należy do rdzenia Orbito. Rdzeń odpowiada na niego wyłącznie przekierowaniem (302 bez treści) i nie uruchamia przy tym kodu modułu. Parametry callbacku trafiają do modułu dopiero później, w kontekście zalogowanego użytkownika.

Podstawą jest bilet: jednorazowy, powiązany z użytkownikiem i firmą rekord, który moduł zakłada tuż przed wysłaniem użytkownika do dostawcy.

Przepływ

  1. Użytkownik klika na stronie modułu przycisk „Połącz”. OVE woła metodę modułu (w kontekście użytkownika).
  2. Metoda tworzy bilet przez OAuth.createTicket i dostaje state oraz redirectUri. Z nich buduje adres zgody dostawcy (redirect_uri, state) i zwraca go do OVE.
  3. Akcja OVE redirect przekierowuje przeglądarkę na ten adres.
  4. Dostawca odsyła przeglądarkę na redirectUri rdzenia. Rdzeń zapisuje wszystkie parametry zapytania na bilecie i przekierowuje przeglądarkę na front Orbito.
  5. Front, z zalogowanym użytkownikiem, kończy bilet. Rdzeń wywołuje metodę finishMethod instancji z { callback, meta, redirectUri }, w kontekście tego użytkownika.
  6. Moduł w finishMethod wymienia kod na token przez Core.fetch i zapisuje tokeny w Config. Potem front przechodzi na stronę returnTo.

Bilet jest jednorazowy: po odebraniu callbacku state jest zużyty, a drugi callback lub drugi finish kończy się błędem. Finish może wykonać tylko użytkownik wskazany przy tworzeniu biletu i tylko w firmie instancji. Chroni to przed podpięciem cudzego konta dostawcy do instalacji innej firmy.

OAuth.createTicket

Tworzy bilet dla bieżącej instancji. Wołaj ją z metody uruchamianej przez użytkownika („Połącz”), tuż przed wysłaniem przeglądarki do dostawcy. Nie wołaj jej przy renderze strony, bo każde wywołanie zużywa bilet. W odróżnieniu od Log, Problems i History metoda odrzuca Promise przy błędzie (np. niepoprawny payload).

const { state, redirectUri, expiresAt } = await OAuth.createTicket(payload);
PoleTypOpis
finishMethodstringNazwa metody tej instancji (zarejestrowanej przez Core.registerMethod), wołanej po powrocie użytkownika od dostawcy, np. oauth.finish
returnToobjectDokąd front przechodzi po finish: { module, path, params? }, jak navigate w OVE. Ustalane przy tworzeniu biletu, callback nie ma na nie wpływu
returnTo.modulestringKod własnego modułu albo core dla strony rdzenia. Każdy inny moduł jest odrzucany
returnTo.pathstringŚcieżka strony w module, np. /settings (1–500 znaków)
returnTo.paramsobjectParametry strony (opcjonalne)
userIdstringUżytkownik, który może zakończyć bilet (24 znaki hex). Wymagane, przekaż ctx.userId metody tworzącej bilet
metaobjectDane zwracane do finishMethod bez zmian (region, sandbox/produkcja itp.), maks. 4 KB po serializacji do JSON. Opcjonalne
ttlnumberIle sekund użytkownik ma na zgodę u dostawcy: 60–1800, domyślnie 600

Wynik:

PoleTypOpis
statestringLosowy identyfikator biletu generowany przez rdzeń. Przekaż go dostawcy w parametrze state
redirectUristringAdres callbacku rdzenia, ten sam, który jest zarejestrowany u dostawcy. Przekaż go jako redirect_uri
expiresAtstringTermin ważności biletu (data ISO)

Pole redirectUri zawsze bierz z wyniku. Nie wpisuj adresu na stałe, dzięki temu ten sam kod działa lokalnie i na produkcji.

Metoda finishMethod

Metoda wskazana w finishMethod jest zwykłą metodą modułu (Core.registerMethod), wołaną przez rdzeń po powrocie użytkownika. Dostaje parametry { callback, meta, redirectUri }:

PoleTypOpis
callbackobjectWszystkie parametry zapytania, które wysłał dostawca (code, error, error_description i inne, specyficzne dla dostawcy)
metaobjectObiekt przekazany do createTicket, bez zmian
redirectUristringTen sam adres co w bilecie. Większość dostawców wymaga jego powtórzenia przy wymianie kodu na token, więc moduł nie musi go przechowywać między krokami

Drugi argument, ctx, to zwykły kontekst użytkownika (userId, permissions), czyli tego, który kliknął „Połącz”.

  • Odmowa po stronie dostawcy (?error=access_denied&error_description=...) przychodzi tą samą drogą. Sprawdź najpierw callback.error i sam zdecyduj, co pokazać.
  • Rzucony błąd oznacza bilet jako failed (bilet jest zużyty), a front pokazuje użytkownikowi komunikat z błędu. Pisz go więc tak, by użytkownik go zrozumiał.
  • Wartość zwrócona przez metodę nie jest używana przez stronę powrotu.

Pełny przykład

Metoda connect tworzy bilet i zwraca adres zgody, a oauth.finish wymienia kod na token:

const { Core, Config, OAuth } = require('@orbito/api-lib');

Core.registerMethod('connect', async (params, ctx) => {
    const { state, redirectUri } = await OAuth.createTicket({
        finishMethod: 'oauth.finish',
        returnTo: { module: 'vendor/shop', path: '/settings' },
        userId: ctx.userId,
        meta: { region: params.region }
    });

    const url = new URL('https://provider.example.com/oauth/authorize');
    url.searchParams.set('client_id', CLIENT_ID);
    url.searchParams.set('response_type', 'code');
    url.searchParams.set('redirect_uri', redirectUri);
    url.searchParams.set('state', state);
    return { url: url.toString() };
});

Core.registerMethod('oauth.finish', async ({ callback, meta, redirectUri }) => {
    if (callback.error) {
        throw new Error(`Dostawca odmówił dostępu: ${callback.error_description || callback.error}`);
    }

    const res = await Core.fetch(`https://api.${meta.region}.provider.example.com/oauth/token`, {
        method: 'POST',
        headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
        body: new URLSearchParams({
            grant_type: 'authorization_code',
            code: callback.code,
            redirect_uri: redirectUri,
            client_id: CLIENT_ID,
            client_secret: CLIENT_SECRET
        }).toString()
    });
    if (res.status !== 200) {
        throw new Error(`Wymiana kodu nie powiodła się (${res.status})`);
    }

    const { access_token, refresh_token, expires_in } = res.json();
    await Config.set('runtime.tokens', {
        accessToken: access_token,
        refreshToken: refresh_token,
        expiresAt: Date.now() + expires_in * 1000
    });
    return { connected: true };
});

Fragment strony OVE z przyciskiem: wynik metody connect ($response.0.url) trafia do akcji redirect:

type: button
title: Połącz
onClick:
  - action: callMethod
    module: vendor/shop
    method: connect
    onSuccess:
      - action: redirect
        url: { valueFrom: $response.0.url }

Biała lista domen

Wymiana kodu na token idzie przez Core.fetch, więc domena endpointu tokenów dostawcy (w przykładzie api.<region>.provider.example.com) musi być na białej liście domen firmy. Sam adres zgody nie wymaga wpisu, bo przeglądarka otwiera go bezpośrednio.

Adres callbacku do rejestracji u dostawcy

Na produkcji createTicket zwraca dziś jeszcze redirectUri o wartości https://v2.orbito.pl/api/oauth/callback. To okres przejściowy: dostawcy mają zarejestrowany stary adres, a ten nadal działa, bo v2.orbito.pl przekierowuje na my.orbi.do. Docelowo będzie to https://my.orbi.do/api/oauth/callback. Jako redirect URI aplikacji u dostawcy rejestruj zawsze dokładnie ten adres, który zwraca createTicket.

Adres zgody zwracany do OVE zawiera & i =, a szablon {{ }} je escapuje. Dlatego w akcji redirect podawaj go przez valueFrom, a nie przez {{ $response.0.url }}.

Ostatnio zaktualizowano:: 25.10.2026, 11:15
Contributors: Wiktor Koźmiński, Claude Fable 5.1
Prev
History
Next
Time