cancel
Showing results for 
Search instead for 
Did you mean: 
Reply
naveenrerd
Frequent Visitor

Call Azure function app from PCF using implicit flow

Hi,

 

I have a azure function with Azure AD authentication. I am not sure on how to trigger the function from PCF component. I tried using msal.js, but that did not work. Azure function is hosted in the same tenant as that of CRM in which I've deployed the PCF. PFB the code I tried. Could you guys help me to authenticate to call the function app.

Here I try to get the token and then planning to use the token with header in the call to Azure Function. I also like to aquire a token without a login popup if possible.

 

 

import { AxiosRequestConfig } from 'axios';
import * as Msal from "msal";

var appConfig = {
    genScope: ["https://url.azurewebsites.net/user_impersonation"]
};

export const msalConfig: Msal.Configuration = {
    auth: {
        clientId: 'bd73****-****-****-****-****74179bb',
        authority: "https://login.microsoftonline.com/0417****-****-****-****-****0dfff06c",
        validateAuthority: false,
        redirectUri: "https://url.azurewebsites.net/.auth/login/aad/callback"
    },
    cache: {
        cacheLocation: "localStorage",
        storeAuthStateInCookie: true
    }
};

const msalInstance = new Msal.UserAgentApplication(msalConfig);

const loginRequest = {
    scopes: appConfig.genScope
};

const tokenRequest = {
    scopes: appConfig.genScope
};

function signIn() {
    msalInstance.loginPopup(loginRequest).then(function (loginResponse) {
        getToken(tokenRequest).then(tk => {
            console.log(tk);
        });
    }).catch(function (error) {
        console.log(error);
    });
}

//acquire a token silently
function getToken(tokenRequest: any) {
    return msalInstance.acquireTokenSilent(tokenRequest).catch(function (error) {
        console.log("aquire token popup");
        // fallback to interaction when silent call fails
        return msalInstance.acquireTokenPopup(tokenRequest).then(function (tokenResponse) {
        }).catch(function (error) {
            console.log("Failed token acquisition", error);
        });
    });
}

msalInstance.handleRedirectCallback((error, response) => {
    // handle redirect response or error
});

export const getTokens = (): Promise<any> => {
    return getToken(tokenRequest);
}

export const runFunction = (): Promise<any> => {
    const requestConfig: AxiosRequestConfig = {
        url: "https://url.azurewebsites.net",
        method: "GET"
    };

    const token = getTokens();
    // use token and call Azure Function APP

    return Promise.resolve(true);
}

 

 

 

9 REPLIES 9
Highlighted
DianaBirkelbach Advocate V
Advocate V

Re: Call Azure function app from PCF using implicit flow

Hi @naveenrerd 

 

My first impulse would be not to call it directly from the PCF.

 

I would try to use a CustomAction, and implement the call to the azure function with a CRM WebHook (or PlugIn), because you don't have authentication issues.

But there is still a problem with calling a CustomAction from the PCF: you need the "execute" method of the webAPI. In the PCF documentation , the WebAPI "execute" method is not documented (but it works), so it's actually unsupported for now. I'm not sure if that is a documentation issue or it's not supposed to work. Another way would be to implement the CustomAction call using the webAPI HttpRequest.

 

It's a very interesting question. I'm also looking forward to see the other answers that will come. 

 

Best regards,

Diana

ben-thompson Impactful Individual
Impactful Individual

Re: Call Azure function app from PCF using implicit flow

@DianaBirkelbach I suspect the reason why execute isn't supported is because it execute could mean very different things in a canvas PCF component compared to a model driven PCF component.

 

The code we use to call an action is just a standard XMLHttpRequest like below (it's hacked from two pieces to give you a promise that makes a post request.

 

var req = new XMLHttpRequest();
		var baseUrl=this.baseUrl;
var query="/api/data/v9.1/hdn_ValidateLicense";
		return new Promise(function (resolve, reject) {

			req.open("POST", baseUrl + query, true);
			req.onreadystatechange = function () {
				
				if (req.readyState !== 4) return;
				if (req.status >= 200 && req.status < 300) {
					
					// If successful
					try {
						
						var result = JSON.parse(req.responseText);
						if (parseInt(result.StatusCode) < 0) {
							reject({
								status: result.StatusCode,
								statusText: result.StatusMessage
							});
						}
						resolve(req.responseText);
					}
					catch (error) {
						throw error;
					}

				} else {
					// If failed
					reject({
						status: req.status,
						statusText: req.statusText
					});
				}

			};
			req.setRequestHeader("OData-MaxVersion", "4.0");
			req.setRequestHeader("OData-Version", "4.0");
			req.setRequestHeader("Accept", "application/json");
			req.setRequestHeader("Content-Type", "application/json; charset=utf-8");
var body=	"{'ProductName': '"+productName+"'}";
			req.send(body);
		});

 

And as you say actions are great ways to avoid security issues (I've often seen security people ask why does this website talk to xyz.com?). By using an action to call the function you bypass that pain and avoid any Cross Domain issues you may hit and you don't want those as debugging that is a complete nightmare as you will need to know the complete settings of a users browsers to identify whether it's an issue, a firewall issue or something else.

 

 

---
If this post has answered your question please consider it for "Accept as Solution" or if it has been helpful give it a "Thumbs Up".
DianaBirkelbach Advocate V
Advocate V

Re: Call Azure function app from PCF using implicit flow

Hi @ben-thompson , 

I agree with you, except that I don't understand the explanation why webAPI.execute is not documented for PCF.

The "feature-usage" webAPI is not available for CanvasApps at all. This is only a Model-Driven App feature. So why should be a difference between webAPI.execute and webAPI.create (for instance)?

 

The problem with self-made requests, is that it is a hard-coded url , at least the "/api/data/v9.1/" part (which will change, at least in version), and that I would need an own library for this requests, if I call it more often.

But I agree, for now is the only supported way for CustomActions.

 

Best regards,

Diana

ben-thompson Impactful Individual
Impactful Individual

Re: Call Azure function app from PCF using implicit flow

The /api/data/v9.1 part is very unlikely to change as removing it would just break a pile of code without any real benefit - I suspect MS will just keep the existing versions going until a breaking change was required (and even then it will require 2 years of notice to avoid pain). 

---
If this post has answered your question please consider it for "Accept as Solution" or if it has been helpful give it a "Thumbs Up".
DianaBirkelbach Advocate V
Advocate V

Re: Call Azure function app from PCF using implicit flow

Thanks @ben-thompson 

I was hoping that the client-side webAPI feature would last longer than the webAPI version (or the endpoint itself), since it could be under the hood shifted to another endpoint (saw a lot of this breaking changes since CRM 1.2).

 

Beside that, I'm not sure if webAPI feature is working offline. The Apps are designed for offline mode too (I know, not really, not for now).

But now thinking about that, I think I just understood why the webAPI feature doesn't have an execute method: in the model-driven sdk (Xrm.WebApi), the execute method is only available for online mode. That would make the difference: the "execute" is not supported for pcf, because the "pcf webAPI feature" doesn't differentiate between online and offline.

But thinking that way, the HttpRequest will not work offline at all. 🤔

 

Best regards,

Diana

naveenrerd
Frequent Visitor

Re: Call Azure function app from PCF using implicit flow

Hi @DianaBirkelbach ,

 

Thanks for your reply. But I would prefer to call the function app directly instead of calling it via a plugin. I am still keeping this issue open.

 

Thanks

PowerMaverick Advocate III
Advocate III

Re: Call Azure function app from PCF using implicit flow

@naveenrerd 

Are you having issues authenticating or invoking Azure Functions? Also this is more of an Azure related question rather than PowerApps. You can call any HTTP request from PCF and that applies to Azure services as well.

You can use MSAL Library for authentication, but I always had issues with it and have been using JQuery/XHR/Fetch for getting the token. Also, I normally would do an App Registrations and create a secret so I do not need to show Login Pop-up. Use registered App's Client Id and created Secret for Basic Auth and retrieve token.

Once, token is retrieved; you can invoke the function (again using JQuery/XHR/Fetch) and pass in the retrieved token as Access Token in the header. 

You can also validate your connections using Postman (which also provides you with code snippets)

Below is the code that will provide you with access_token which can be used as a Bearer Token when calling Azure Function.

 

const getAuthenticationToken = async function() {
    let config = require(__dirname + "/../config/config.json");
    var request = require('request');
    var options = {
        'method': 'POST',
        'url': 'https://login.microsoftonline.com/' + config.tenantId + '/oauth2/token',
        'headers': {
            'Authorization': 'Basic ' + new Buffer(config.clientId + ":" + config.clientSecret).toString('base64'),
            'Content-Type': 'application/x-www-form-encoded'
        },
        form: {
            'grant_type': 'client_credentials',
            'resource': 'your Azure function URL'
        }
    };

    return new Promise(
        (resolve, reject) => {
            request(options, function (error, response) {
                if (error) {
                    reject(error);
                }
                resolve(JSON.parse(response.body));
            });
        }
    );
}

module.exports.getAuthenticationToken = getAuthenticationToken;

 


----
Danish Naglekar | Power Maverick
If this post helps, then please consider Accept it as the solution to help the other members.

naveenrerd
Frequent Visitor

Re: Call Azure function app from PCF using implicit flow

Hi @PowerMaverick ,

 

Thank you for you suggestion. As I am using frontend code, I cannot expose client secret as any user can read the client secret. This is again a security vulnerability. I am expecting something like aadhttp which SharePoint provides along with context so that AAD can be accessed with current logged in users.

 

Thanks,

Naveen Kumar Ravichandran

rajyraman Kudo Collector
Kudo Collector

Re: Call Azure function app from PCF using implicit flow

@naveenrerd- You could follow a similar approach to this https://taerimhan.com/consuming-microsoft-graph-api-from-pcf-control/. Although this is for Graph API, the approach is something that you could use to execute Functions protected by Azure AD using the same MSAL library.

Helpful resources

Announcements
MBAS Gallery 2020

MBAS Gallery 2020

Watch Microsoft Business Applications Summit sessions on-demand.

‘Better Together’ T-Shirt Contest – Winner Announced!

‘Better Together’ T-Shirt Contest – Winner Announced!

And the winner is...

firstImage

New Ranks and Rank Icons released on April 21!

The time has come: We are finally able to share more details on the brand-new ranks coming to the Power Apps Community!

Power Platform 2020 release wave 1 plan

Power Platform 2020 release wave 1 plan

Features releasing from April 2020 through September 2020

Users online (6,066)