Forum Discussion

joseph_singh_fr's avatar
joseph_singh_fr
Frequent Visitor
1 year ago
Solved

Power BI custom connector Token exchange in header

Hello All,   I have built a Power BI cutom connector for a REST API SPIDER CMDB service. However, I am having issues with the authentication. My issue is made worst, as I need to be able to publish...
  • Anonymous's avatar
    Anonymous
    1 year ago

    Hi joseph_singh_fr ,

    Instead of “hardcoding” user name and password and then using Anonymous authentication, you should have your connector obtain the credentials at run‐time (from the data source settings) and then perform the token exchange in M. First create the function below to obtain the credentials that the user has supplied and then calls the token endpoint by sending a proper header:

    GetFinalToken = (Server as text, SpiderApiInstance as text) as text =>
      let
        // Get the credentials from the data source settings.
        // When using “Basic” authentication, Extension.CurrentCredential() returns a record with Username and Password.
        Credentials = Extension.CurrentCredential(),
    
        // Extract username and password
        Username = Credentials[Username],
        Password = Credentials[Password],
    
        // Create base64-encoded Basic header (make sure to choose Base64 encoding)
        BasicToken = "Basic " & Binary.ToText(Text.ToBinary(Username & ":" & Password), BinaryEncoding.Base64),
    
        // build the URL to the token endpoint; note: do not embed credentials in the URL
        TokenUrl = "https://" & Server & "/" & SpiderApiInstance & "/token",
    
        // Make the call to the token endpoint.
        // Notice that we include a set of headers (including our Auth header) for our token request.
        TokenResponse = Web.Contents(TokenUrl, [
             Headers = [
                #"Content-Type" = "application/json",
                #"Authorization" = BasicToken,
                #"Accept" = "application/json",
                #"Cache-Control" = "no-cache"
             ]
        ]),
    
        // Extract the metadata headers which include the final token.
        ResponseHeaders = Value.Metadata(TokenResponse)[Headers],
        FinalToken = ResponseHeaders[Token]
      in
        FinalToken;

    Then in the main query function call GetFinalToken to obtain the token and use it for subsequent calls:

    MyAPIQuery = (Server as text, SpiderApiInstance as text, resourcePath as text) as any =>
      let
        // Get the final token using the helper function.
        FinalToken = GetFinalToken(Server, SpiderApiInstance),
        
        // Now build the header that will be passed when calling the secured resource.
        AuthTokenHeader = "Bearer " & FinalToken,
        
        ResourceUrl = "https://" & Server & "/" & SpiderApiInstance & "/" & resourcePath,
        
        // Make the secured call with the token in the header.
        Response = Web.Contents(ResourceUrl, [
             Headers = [
                #"Content-Type" = "application/json",
                #"Accept" = "application/json",
                #"Authorization" = AuthTokenHeader
             ]
        ]),
        Result = Json.Document(Response)
      in
        Result;

    Best Regards