tl;dr když pracuješ s API v Power Query, je důležité znát několik autentizačních metod: Anonymous, API Key, Bearer Token, Basic a OAuth 2.0. Většina z těchto metod vyžaduje autorizační hlavičku v rámci funkce Web.Contents(). V tomto článku se dozvíš, jak zvládnout všech těchto pět metod. Existují i další, méně časté metody (v Power Query), o kterých nebudeme podrobně mluvit, ale připojil jsem odkaz, pokud se o nich chceš dozvědět více.

Autentizace vs. Autorizace

Určitě ses s oběma termíny už setkal. Ikdyž je občas někdo používá jako jeden termín, pravdou je, že jsou to dva rozdílné pojmy.

  • Autentizace je proces ověřování identity uživatele, systému nebo entity. Jejím hlavním cílem je odpovědět na otázku: „Kdo jsi?“ Uživatel obvykle poskytuje přihlašovací údaje, jako je uživatelské jméno a heslo, bezpečnostní token nebo dokonce biometrická data, například otisk prstu.
  • Autorizace, na druhé straně, je proces určování, jaké akce, zdroje nebo služby může autentizovaný uživatel používat. Zaměřuje se na otázku: „Co máš povoleno dělat?“ Například uživatel může mít oprávnění zobrazit a upravit dokument, přistupovat ke specifickým API endpointům nebo pracovat s určitou databází.

Authentication types

V dnešním článku se zaměřímě na nejčastějí typy API autentizace, které, teoreticky, se dají implementovat v Power Query, specificky se dají napsat v jazyku M.

Poznámka; Power Query obsahuje spoustu nativně podporovaných konektorů, které disponují uživatelským oknem pro zvolení typu autentizace. Nicméně, v tomto článku se zaměříme na takové konektory, které toto okno implementované nemají a musíme je napsat pomocí jazyka M, konkrétně API zdroje.

Seznam základní typů autentizace, na které mrkneme:

Symbol kotvy tě pošle na část článku se zvoleným typem

Seznam ostatních typů, které zde probírat nebudeme:

Autentizace v Power Query

V Power Query se většinou spoléháme na okno, které nám dovoluje pro nativní konektory zvolit autentizační způsob pomocí “myši”, případně ho jednoduše zadat do připravených polí.

Známé okno, které nám umožní zvolit autentizační metodu.

Pokud se chceme připojit ke zdroji, který není zahrnut mezi nativní možnosti, musíme si vytvořit toto „autentizační okno“ sami pomocí jazyka M. Bez ohledu na zdroj tě Power Query stále vyzve k výběru metody autentizace prostřednictvím grafického rozhraní. Abychom mohli metodu definovat ručně v jazyce M (zejména pomocí hlavičky Authorization), je nutné v grafickém autentizačním okně vybrat možnost „Anonymous“. Tato volba nám umožní specifikovat požadovanou metodu autentizace přímo v kódu M. Pokud nevybereš Anonymous a přesto definuješ hlavičku Authorization, zobrazí se tato chybová zpráva:

Expression.Error: The 'Authorization' header is only supported when connecting anonymously. These headers can be used with all authentication types: Accept, Accept-Encoding, Accept-Charset, Accept-Language, Cache-Control, Content-Type, If-Modified-Since, Prefer, Range, Referer

Jestli chceš tenhle problém vyřešit, přejdi do Nastavení zdroje dat, najdi svůj zdroj, klikni na Upravit oprávnění, poté na Upravit a vyber možnost Anonymous (jak je znázorněno na obrázku výše).

Implementace v Power Query

Anonymous

Autentizace typu Anonymous umožňuje uživatelům přistupovat ke zdroji dat bez zadání jakýkoliv přihlašovacích údajů. Tento typ autentizace se v business sféře používá jen zřídka. Naopak je běžně využíván u veřejně dostupných informací, jako jsou volně přístupné databáze nebo sbírky obsahu – například obrázky koťat 🐈. Můžeme mrknout na obě sbírky.

Pokud jsi nikdy nepracoval s API v Power Query, mrkni nejdřív na tento článek.

Příklad obecného zápisu:

let
    request = Json.Document(
        Web.Contents(
            "url",
            [
                RelativePath = "relativePath"
            ]
        )
    )
in
    request 

Příklad 1 (Veřejná databáze zranitelností):

let
    sourceVulnerabilities = Json.Document(
        Web.Contents(
            "https://services.nvd.nist.gov",
            [
                RelativePath = "rest/json/cvehistory/2.0"
            ]
        )
    )
in
    sourceVulnerabilities
Response

Příklad 2 (Veřejná kolekce obrázků koček):

let
    sourceCat = Json.Document(
        Web.Contents(
            "https://api.thecatapi.com",
            [
                RelativePath = "v1/images/search?",
                Query = [limit = "1"]
            ]
        )
    ),
    firstRecord = sourceCat{0} // {0} vezme první záznam z dané kolekce
in
    firstRecord
Response

Jak vidíš, vytvořili jsme jednoduchý HTTP požadavek bez nutnosti Autorizační hlavičky.

API Key

Tato metoda zahrnuje použití statického klíče, obvykle bez data expirace, který je často generován prostřednictvím dokumentačního portálu nebo uživatelského rozhraní poskytovatele API. Pro vygenerování klíče budeš pravděpodobně potřebovat uživatelský účet s konkrétními oprávněními, aby klíč zajistil přístup ke všem potřebným zdrojům. Tento přístup je jednoduchý a vhodný pro bezplatná nebo veřejná API. Jeho největší nevýhodou však je, že jelikož je klíč často bez data vypršení, jeho náhodný únik může znamenat nevyžádaný přístup k tvým datům z třetích stran.

V Power Query používáme dva způsoby, jak se ověřit pomocí API Key:

  • Hlavička požadavku: Můžeš vepsat klíč do speciálního x-api-key headeru.
let
    request= Json.Document(
        Web.Contents(
            "url",
            [
                RelativePath = "relativePath",
                Headers = [
                    #"x-api-key" = "vygenerovaný API Key"
                ]
            ]
        )
    )
in
    request

Někdy můžeš vidět i využití v rámci Autorizačního headeru: Authorization=ApiKey tvůjklíč

  • Query Parametr: Případně můžeš vepsat klíč i jako jeden z parametrů “query stringu”, tento parametr se nazývá: api_key.

Pozor; odesílání API klíče prostřednictvím dotazovacího řetězce (query string) je nebezpečné, protože může být zaznamenáno v URL adresách nebo serverových logech. Pokud je to možné, používej místo toho autorizační hlavičku nebo jiné bezpečnější metody.

let
    request = Json.Document(
        Web.Contents(
            "url",
            [
                RelativePath = "relativePath",
                Query = [
                    api_key ="vygenerovaný API Key"
                ]
            ]
        )
    )
in
    request

Pro příklad, předchozí Cat API nám dovoluje využít i API Key jako způsob autentizace:

V obou případech se náš klíč schovává pod parametrem: “cat_api_key”

Příklad 1 (hlavička požadavku):

let
    sourceCat = Json.Document(
        Web.Contents(
            "https://api.thecatapi.com",
            [
                RelativePath = "v1/images/search?",
                Query = [
                    limit = "1"
                ],
                Headers = [
                    #"x-api-key" = cat_api_key
                ]
            ]
        )
    ),
    firstRecord = sourceCat{0} // {0} vezme první záznam z dané kolekce
in
    firstRecord

Příklad 2 (query parameter/string):

let
    sourceCat = Json.Document(
        Web.Contents(
            "https://api.thecatapi.com",
            [
                RelativePath = "v1/images/search?",
                Query = [
                    limit = "1",
                    api_key = cat_api_key
                ]
            ]
        )
    ),
    firstRecord = sourceCat{0} // {0} vezme první záznam z dané kolekce
in
    firstRecord

Bearer Token

Bearer tokeny jsou běžnou metodou pro efektivní přístup k API. Jedná se o generovaný token, který se používá v hlavičce Authorization s předponou “Bearer”. I když se mohou zdát podobné API klíčům, největší rozdíly spočívají v jejich životnosti a metodách generování. Bearer tokeny lze regenerovat prostřednictvím uživatelského účtu na webu poskytovatele API (podobně jako API klíče), často s možností nastavit datum expirace. Bezpečnějším přístupem je přidat další vrstvu ochrany pomocí krátkodobých obnovovacích tokenů (refresh tokens), které obvykle expirují během několika minut.

Příklad obecného zápisu:

let
    request = Json.Document(
        Web.Contents(
            "url",
            [
                RelativePath = "relativePath",
                Headers = [
                    Authorization = "Bearer test_token"
                ]
            ]
        )
    )
in
    request

Pro reálný příklad, použijeme existující testovací API:

let
    request = Json.Document(
        Web.Contents(
            "https://httpbin.org",
            [
                RelativePath = "bearer",
                Headers = [
                    Authorization = "Bearer test_token"
                ]
            ]
        )
    )
in
    request

Basic

Tato metoda je velmi podobná běžnému zadávání uživatelského jména a hesla, jaké znáš z formulářů. Je zde však jeden další krok: musíš zformátovaný řetězec user:password zakódovat do formátu Base64. Podobně jako u Bearer tokenu se také používá hlavička Authorization s klíčovým slovem jako předponou – v tomto případě “Basic”.

Pozor! Kódování není totéž co šifrování, takže pokud někdo získá tvůj zakódovaný řetězec, může jej snadno dekódovat. Zveřejnění takového řetězce mimo tvoji organizaci představuje bezpečnostní riziko, podobně jako bys metaforicky nechal na stole papírek s uživatelským jménem a heslem. Z tohoto důvodu některá API využívají generované časově omezené tokeny spárované s tvým uživatelským jménem, přičemž výsledný řetězec je zakódován ve formátu username:token.

Příklad obecného zápisu:

let
    user = "user", // příklad: user@org.com
    password = "password", // heslo nebo vygenerovaný token
    base64 = Binary.ToText(Text.ToBinary(user & ":" & password), BinaryEncoding.Base64), // zakóduj to do Base64
    request = Json.Document(
        Web.Contents(
            "url",
            [
                RelativePath = "relativePath",
                Headers = [
                    Authorization = "Basic " & base64
                ]
            ]
        )
    )
in
    request

Pro tento způsob autentizace nemám dobrý reálný veřejný příklad, nicméně pokud jsi někdy pracoval s JIRA Cloud, mrkni, jak například získáš úkoly přiřazené na tebou použitý účet:

let
    user = "user@myorg.com", // vyměnit za za váš email
    password = "generated_token_through_your_profile", // vyměnit za váš API token
    base64 = Binary.ToText(Text.ToBinary(user & ":" & password), BinaryEncoding.Base64), // Encode user:password to Base64
    request = Json.Document(
        Web.Contents(
            "https://myorg.atlassian.net",
            [
                RelativePath = "rest/api/3/search?",
                Query = [
                    jql = "assignee=currentUser()",
				  fields = "created,summary"
                ],
                Headers = [
                    Authorization = "Basic " & base64
                ]
            ]
        )
    )
in
    request

OAuth 2.0

Tak, pojďme mrknout na současného krále autentizace. OAuth 2.0 je otevřený standard pro autorizaci, který umožňuje aplikacím přistupovat k uživatelským datům jménem uživatele, aniž by musely mít přístup k jeho přihlašovacím údajům. Funguje tak, že vydává přístupové tokeny třetím stranám poté, co uživatel udělí souhlas prostřednictvím autorizačního serveru. Tyto tokeny se pak používají v API požadavcích k bezpečnému přístupu k chráněným zdrojům.

Jednoduše řečeno. Místo toho, abys třetí straně přímo poskytl své uživatelské jméno a heslo, projdeš přes důvěryhodnou službu autentizace, kde udělíš aplikaci povolení přistupovat pouze k určitým částem tvých dat. Aplikace pak obdrží speciální klíč (přístupový token), který jí umožní provádět jen ty akce, které jsi schválil. Tvoje přihlašovací údaje tak zůstávají v bezpečí a máš kontrolu nad tím, k čemu má aplikace přístup.

Tato metoda je často používána při práci s Microsoft API, například s Power BI REST API. Proces začíná registrací tvojí aplikace v Azure Portal, kde získáš potřebné klientské údaje, jako je client ID a client secret. Tyto údaje následně použiješ k žádosti o přístupový token pro třetí stranu, v tomto případě Power BI REST API. Přístupový token se obvykle chová jako Bearer token, takže jej zahrneš do hlavičky Authorization API požadavků ve formátu: “Bearer generated_token”. Tím aplikace bezpečně přistupuje k API jménem uživatele, aniž by potřebovala jeho přihlašovací údaje.

I když se počáteční požadavky na získání přístupového tokenu mohou lišit podle konkrétní služby, sdílí obvykle podobnou strukturu. Zde je obecný příklad:

let
    // Sestav tělo požadavku jako záznam s potřebnými parametry pro získání tokenu
    requestBodyQuery = [
        grant_type = "<grant_type>", 
        // Typ požadovaného grantového procesu (např. client_credentials)

        client_id = "<client_id>",
        // Client ID tvojí aplikace

        client_secret = "<client_secret>", 
        // Client Secret tvojí aplikace

        scope = "<scope>"                   
        // Rozsah přístupu, který požaduješ
    ],
    
    // Převést tělo požadavku na URL-kódovaný řetězec požadovaný pro POST požadavek
    requestBodyContent = Text.ToBinary(Uri.BuildQueryString(requestBodyQuery)),
    
    // Vytvoř HTTP POST požadavek na token endpoint
    request = Json.Document(
        Web.Contents(
            "url", // Nahraď základní URL endpointu pro token
            [
                RelativePath = "relativePath", // Nahraď specifickou cestu k token endpointu
                Headers = [
                    #"Content-Type" = "application/x-www-form-urlencoded" // Urči typ obsahu pro URL-kódovaná data
                ],
                Content = requestBodyContent // Zahrň URL-kódované tělo do požadavku
            ]
        )
    ),
    
    accessToken = request[access_token] // Získá hodnotu "access_token" z JSON odpovědi
in
    accessToken

Nejdůležitější částí je tělo požadavku. Zde specifikuješ informace o registrované aplikaci, například její client_secret a client_id. Poté použijeme obsah (Content) a hlavičku Content-Type, abychom funkci předali nově vytvořený dotaz. Použil jsem funkci Uri.BuildQueryString, která přijímá záznam a převádí jej na jednoduchý URI řetězec. Hlavním přínosem této funkce je pomoc s escapováním speciálních znaků a kombinací polí pomocí ”&”. Výsledný escapovaný a kombinovaný záznam vypadá takto:

grant_type=%3Cgran_type%3E&client_id=%3Cclient_id%3E&client_secret=%3Cclient_secret%3E&scope=%3Cscope%3E

Můžeme použít tento typ, protože jsme specifikovali Content-Type jako application/x-www-form-urlencoded (též známo jako typ MIME). Tento typ požaduje páry “jméno-hodnota”, proto jsme vytvořili jednoduchý záznam s poli a jejich hodnotami.

Obecný zápis vypadá takto:

field1=value1&field2=value2&field3=value3

Tato část je potom přeložena do toku bytů (binary data), skrz definici těla požadavku. V Power Query používáme funkci Text.ToBinary() pro přeložení dat.

Pokud bychom použili reálný příklad, dostali bychom něco takového:

Jako odpověď dostaneme token_type jako Bearer (poukazuje na to, že později využijeme předponu “Bearer ”), informaci o vypršení tokenu - expiration (platný na jednu hodinu), a pak vlastní access_token, který potom použijeme pro volání aplikace třetí strany.

Pro dokončení volání aplikace třetí strany, přepoužijeme to, co jsme se naučili v sekci o Bearer tokenu, kde token právě nahradíme naším nově vygenerovaným access_token(em).

let
    request = Json.Document(
        Web.Contents(
            "url",
            [
                RelativePath = "relativePath",
                Headers = [
                    Authorization = "Bearer acess_token"
                ]
            ]
        )
    )
in
    request

Abych ti poskytl malou ukázku, jak vytvořit OAuth 2.0 pro aplikaci specifickou pro Microsoft, v tomto případě Power BI REST API, můžeš se inspirovat tímto příkladem:

let
    requestBodyQuery = [
        grant_type = "client_credentials",
        client_id = "<client_id>", // nahradit
        client_secret = "<client_secret>", // nahradit
        scope = "https://analysis.windows.net/powerbi/api/.default"
    ],
    
    requestBodyContent = Text.ToBinary(
        Uri.BuildQueryString(requestBodyQuery)
    ),
    
    request = Json.Document(
        Web.Contents(
            "https://login.microsoftonline.com",
            [
                RelativePath = "<yourorg>.onmicrosoft.com/oauth2/token", // napsat svoji organizaci
                Headers = [
                    #"Content-Type" = "application/x-www-form-urlencoded"
                ],
                Content = requestBodyContent
            ]
        )
    ),
    
    accessToken = request[access_token]
in
    accessToken

S výsledným accessToken(em), můžeš vytvořit požadavek například pro Power BI REST API Get Activity Events, zde píšu, jak na to více do hloubky.

Shrnutí

Prozkoumali jsme pět autentizačních metod v Power Query. Typ autentizace Anonymous nevyžaduje přihlašovací údaje a je vhodná pro veřejná data. API Key využívá unikátní klíč poskytnutý API, který je nutné udržovat v bezpečí. Bearer Token zahrnuje tokeny s nastavitelnou životností, které se přidávají do hlavičky Authorization jako “Bearer <token>”, což zvyšuje bezpečnost díky expiraci a obnovování tokenů. Basic authentication odesílá Base64-kódované uživatelské jméno a heslo v hlavičce Authorization a měla by být používána pouze přes zabezpečené připojení. Nakonec OAuth 2.0 poskytuje bezpečný přístup bez sdílení osobních přihlašovacích údajů pomocí přístupových tokenů získaných důvěryhodným autorizačním procesem. Každá metoda nabízí různé úrovně bezpečnosti a je vhodná pro různé scénáře při připojování ke zdrojům dat v Power Query.