Guest Blog: Build Custom API on Microsoft Flow and PowerApps with Authentication
We came across a great blog post by our colleague Tsuyoshi Matsuzaki from Microsoft Japan. Tsuyoshi Matsuzaki is a technical evangelist whose mission is educating and supporting ISV developers on Microsoft Azure, Office 365 , and other enterprise platforms.
Thanks Tsuyoshi, on behalf of the PowerApps team!
———————————————————————————————-
The custom api enables you to connect your own web api (REST api) in Microsoft Flow (including SharePoint workflow) and PowerApps. You can connect Microsoft Flow and PowerApps with your in-house applications or unknown 3rd party (ISV) applications.
In this post I show you how to build and use the custom api, and in most cases the authentication is needed, then I also explain with real authentication scenario. (First I explain using Azure AD, and next I show you the other cases, such as Google account.)
Build your own web api
In the first example, we use the Azure Active Directory (Azure AD) as the authentication provider with custom api.
In this case, your web api must handle the OAuth access token.
I don’t describe how to build the web api secured by the Azure AD, but if you’re using ASP.NET Web API, you just click [Change Authentication] button in the project creation wizard and set-up the Azure AD information. (See the following screen.)
If you’re using other programming language, see “How to build API secured by Azure AD” (Japanese) in my previous post.
Note : You can also use the Azure App Service (API App) and [Authentication / Authorization] settings (so called “Easy Auth”) for every programming languages.
See “Authentication and authorization in Azure App Service” for details.
Next you must prepare the swagger specification file (json file).
If you use ASP.NET Web API, you can insert “Swashbuckle” Nuget package and download this json by accessing http://{your root URL}/swagger/docs/v1.
The next is one of the swagger specification example. Especially, you must remember operationId value (the following “Values_Get”), because we use this operation in the PowerApps later.
In the swagger specification, you must add the following “securityDefinitions” section, and set Azure AD authentication information as follows.
{ "swagger": "2.0", "info": { "version": "v1", "title": "TestApi01" }, "host": "demo.azurewebsites.net", "schemes": [ "https" ], "paths": { "/api/Values/{id}": { "get": { "tags": [ "Values" ], "operationId": "Values_Get", "consumes": [ ], "produces": [ "application/json", "text/json", "application/xml", "text/xml" ], "parameters": [ { "name": "id", "in": "path", "required": true, "type": "integer", "format": "int32" } ], "responses": { "200": { "description": "OK", "schema": { "type": "string" } } } }, . . . } }, "definitions": { }, "securityDefinitions": { "oauth2": { "type": "oauth2", "flow": "implicit", "authorizationUrl": "https://login.windows.net/common/oauth2/authorize", "scopes": { } } } }
If you use Swashbuckle in your ASP.NET Web API project, you just insert the following code (bold font) in App_Start\SwaggerConfig.cs.
public class SwaggerConfig { public static void Register() { var thisAssembly = typeof(SwaggerConfig).Assembly; GlobalConfiguration.Configuration .EnableSwagger(c => { c.SingleApiVersion("v1", "TestApi01"); . . . c.OAuth2("oauth2") .AuthorizationUrl("https://login.windows.net/common/oauth2/authorize") .Flow("implicit") .Scopes(scopes => { //scopes.Add("xxxxx", "Some access to protected resources"); }); }) .EnableSwaggerUi(c => { . . . }); } }
Register APIs in Azure AD
In the case of Azure AD, the custom api proxy in the Microsoft Flow or PowerApps retrieves the access token for your web api resource, and calls your web api by setting this token in the http header.
i.e, you must register both the custom api proxy app and your web api app in the Azure AD, and set the permission between custom api proxy and your web api.
Note : If you have used the previous [Change Authentication] button in ASP.NET Web API, the web api app is already registered in Azure AD.
The following illustrates this.
When you register the custom api proxy (Azure AD app of Microsoft Flow or PowerApps side), you must add the following url (fixed value) as the redirect url. Both Microsoft Flow and PowerApps uses this redirect url, when processing OAuth.
https://msmanaged-na.consent.azure-apim.net/redirect
Currently (in Nov 2016), the Azure AD v2 endpoint is not supported (but v1 only) for this scenario, and you must use the Azure Classic Portal (https://manage.windowsazure.com/), not Azure Ibiza Portal (https://portal.azure.com).
And you must set the custom api proxy’s permissions for accessing your web api in the Azure Classic Portal. (You cannot set this permission and cannot see the resource id in the Ibiza portal today.)
See the following screenshot.
Note : Strictly speaking, v2.0 endpoint (Azure AD v2 endpoint) is supported in the custom api. But, this proxy and web api flow (see the illustration above) is not supported for v2.0 endpoint.
Please refer the next Google scenario (flow) for the v2.0 endpoint.
How to work (or use) in PowerApps
Now you’re ready to use the custom api in Microsoft Flow and PowerApps. Here I show you the step of setting PowerApps.
Note : For the details of this procedure, please refer the official document “Register Custom APIs in PowerApps“.
First you login to PowerApps (https://web.powerapps.com/), and select [Connections] in the navigation, and click [New connection].
Select [Custom] tab and click [New custom API].
In the next window, upload the swagger specification file (json) previously created.
The swagger specification is parsed and the identity provider is auto-detected by the PowerApps.
You must set some api information in the next window like the following screenshot. Note that this client id and secret is for the previous custom api proxy, not your web api. The Resource URL (the accessing scopes) is the ID/URI of your web api, not the custom api proxy.
The connection settings of the custom api has done. Next you start to create the app in the PowerApps.
Click [New App] button, and select [Phone layout] in the [Blank app].
In the design window, select [Content] – [Data sources] menu.
The data source window is displayed in the right pane, and click [Add data source] button, and [New connection] button.
You can find the previously created custom api, and select (connect) that.
Then the Azure AD sign-in UI is displayed, and you must enter your credential.
The custom api is inserted as the data source.
Let’s test this custom api !
Please insert the button control into your app, and input the following expression as the button “OnSelect” function (fx).
This is calling the “ValuesGet” method (see the previous “operationId” in the swagger file) in the custom api named “TestApi01”, and setting the string result in the context variable named “ResultValue”.
UpdateContext( { ResultValue : TestApi01.ValuesGet(3) } )
Note : You can use auto-correct or suggestions when you’re writing functions.
Next you insert the text box, and set “ResultValue” (the context variable previously created) in the text box function.
Push run button, and this app is launched in the web browser.
When you push the button in the app, your web api is called by the PowerApps and the returned value is displayed in the text box.
In the backend, the following http request is called against your web api.
Then your web api can verify the token (the following “Authorization” header value) and retrieve the claims. Please see “Protect a Web API using Bearer tokens from Azure AD” for this programming when you’re using ASP.NET Web API..
GET /api/Values/3 Accept: */* Authorization: Bearer eyJ0eXAiOi... Origin: https://us.create.powerapps.com X-Ms-Apim-Tokens: ew0KICAidG...
HTTP/1.1 200 OK Content-Type: application/json; charset=utf-8 "you entered 3"
Note : The “X-Ms-Apim-Tokens” header is also important, and I explain this later. (In the case of Azure AD, there’s no need to use this token.)
This token (“Authorization” header value) is the Azure AD access token itself. Then you can also get the access token for another resources in your web api by calling the following OAuth on_behalf_of flow.
That is, your web api can collaborate another Azure AD resources like Office 365 API, Azure ARM REST, Power BI REST, etc.
POST https://login.microsoftonline.com/common/oauth2/token Content-Type: application/x-www-form-urlencoded grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Ajwt-bearer&assertion={received access token}&requested_token_use=on_behalf_of&resource={resource id that your api wants to access}&scope=openid&client_id={client id of your web api}&client_secret={client secret of your web api}
You can share your app to other people in the same organization.
The sign-in for this custom api, i.e, Azure AD sign-in is needed, when the user launch this app for the first time. (see the following screenshot)
Other Providers (the case of Google)
You can also use the OAuth 2.0 of Google, Facebook, Salesforce and other SaaS applications including the generic OAuth 2.0 providers. (see the official document “Register Custom APIs in Microsoft Flow“. The flow by API Key and Basic Authentication are also supported.)
Let’s see the case of Google account.
Google and most providers are not having api registration, only client registration. (Except for the app context like api key.)
Therefore, you register only the custom api proxy as OAuth client into Google Developer Console, get access token for pre-defined Google scopes only (profile, email, etc), and pass this token to your web api. (Or you could use the api key instead.)
Next is the swagger example for Google account settings. (see the bold font)
{ "swagger": "2.0", "info": { "version": "v1", "title": "TestApi01" }, "host": "demo.azurewebsites.net", "schemes": [ "https" ], "paths": { "/api/Values/{id}": { "get": { "tags": [ "Values" ], "operationId": "Values_Get", "consumes": [ ], "produces": [ "application/json", "text/json", "application/xml", "text/xml" ], "parameters": [ { "name": "id", "in": "path", "required": true, "type": "integer", "format": "int32" } ], "responses": { "200": { "description": "OK", "schema": { "type": "string" } } } }, . . . } }, "definitions": { }, "securityDefinitions": { "oauth2": { "type": "oauth2", "flow": "accessCode", "authorizationUrl": "https://accounts.google.com/o/oauth2/auth", "tokenUrl": "https://www.googleapis.com/oauth2/v4/token", "scopes": { } } } }
PowerApps (or Microsoft Flow) automatically detects Google account, and when you connect to the custom api, the Google account login is displayed as the following screenshot.
Next is the http request for your web api.
It is the same like Azure AD, but not. The “Authorization” header value is the access token for Google scopes, not for your web api.
GET /api/Values/3 Accept: */* Authorization: Bearer ya29.Ci-aAy... Origin: https://us.create.powerapps.com X-Ms-Apim-Tokens: ew0KICAidG...
Therefore you cannot verify this access token in your web api, but you can verify the login user instead of using X-Ms-Apim-Tokens. This token (X-Ms-Apim-Tokens) is the Base64 Url encoded value (see RFC 4648) of the following json string, and as you can see, the value includes the refresh token and id token of Google account. As a result, you can decode the id token value, and retrieve the user claims, verify the digital signature.
{ "token": { "AccessToken": "ya29.Ci-aAy...", "ExpiresIn": "3600", "IdToken": "eyJhbGciOi...", "RefreshToken": "1/udVjULwb...", "TokenType": "Bearer", "OAuth2TokenEndPointCredentialLocation": "Body", "ExpiresOn": "636150505441694110", "LoginSettingId": "msmanaged-na_customapidemo02.5f989...", "TokenAcquireTime": "11/18/2016 6:22:24 AM" }, "sku": "Enterprise", "$connectionCreator": { "objectId": "cf258756-2623-47cb-be46-c85d436265bb", "tenantId": "3c839350-a414-442a-9585-8db0b0f5f300", "userPrincipalName": "tsmatsuz@o365directory.onmicrosoft.com" }, "$ConnectionKey": "Key eyJ0eXAiOi...", "$callerIdentity": { "objectid": "cf258756-2623-47cb-be46-c85d436265bb", "prinicipaltype": "ActiveDirectory", "tenantid": "3c839350-a414-442a-9585-8db0b0f5f300", "email": "tsmatsuz@o365directory.onmicrosoft.com" } }
If your web api doesn’t need the login user, you could use the api key instead.
———————————————————————————————-