Azure Functions and App Service Authentication with Auth0 and other OpenID Connect providers
Thursday, July 23, 2020
Azure Functions and Azure App Service recently added integration with OpenID Connect (OIDC) providers. We can now use any OpenId Connect compliant provider to authenticate users in our apps.
In this article, we'll look at how to configure Auth0 with Azure Functions. The same steps can be used to configure any other OIDC provider and can also be applied to Azure App Service.
Overview
To integrate an OpenID Connect provider with Azure Functions, we need to follow these steps:
- Obtain a client id and secret plus other config settings from the OIDC provider.
- Create an authentication config file in our app and add the relevant information from the OIDC provider to the file.
- Supply the client secret in an app setting.
- Enable file-based authentication configuration in the app.
Create an app in Auth0
Auth0 is a popular identity service. It supports login via many social identities as well as with app-specific accounts.
Instead of configuring our function app with social logins like Google or creating a custom username/password database solution, we can rely on Auth0 to manage all that for us and we simply integrate our app with Auth0 using OpenID Connect.
The first thing we need to do to get started is create a free Auth0 account. Then we create an app in Auth0 of type "Regular Web Application".
When the app is created, note the client id and secret.
Note: We need to create a function app in Azure before proceeding with the following steps. Auth0 is going to need to use the app name in some configurations.
In the Application URIs section, fill in these settings:
- Application Login URI -
https://<app-name>.azurewebsites.net/.auth/login/auth0
- Allowed Callback URLs -
https://<app-name>.azurewebsites.net/.auth/login/auth0/callback
- Allowed Logout URLs -
https://<app-name>.azurewebsites.net/.auth/logout
The most important setting is the Allowed Callback URLs, which tells Auth0 about the callback URL that the function app authentication will use.
Note that each URL has a segment with the value auth0
. This needs to match the name we give the OIDC provider in the configuration file that we'll cover next.
Click Save Changes. Then click on the subtle Show Advanced Settings link.
In the Endpoints tab, note the OpenID Configuration URL.
Create an authentication config file
Currently, OpenID Connect providers can only be enabled in Azure Functions or App Service using a new file-based configuration. Multiple providers can be configured in the same app.
The config file must be located in the root of the function app. We'll create one named auth.json.
Then we place this content in the file:
{
"platform": {
"enabled": true
},
"globalValidation": {
"redirectToProvider": "auth0",
"unauthenticatedClientAction": "RedirectToLoginPage"
},
"identityProviders": {
"openIdConnectProviders": {
"auth0": {
"registration": {
"clientId": "<auth0_client_id>",
"clientCredential": {
"secretSettingName": "AUTH0_CLIENT_SECRET"
},
"openIdConnectConfiguration": {
"wellKnownOpenIdConfiguration": "https://<auth0_tenant_name>.auth0.com/.well-known/openid-configuration"
}
},
"login": {
"nameClaimType": "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name",
"scope": [ "openid", "profile", "email" ],
"loginParameterNames": []
}
}
}
},
"login": {
"tokenStore": {
"enabled": true
}
}
}
Replace the values of clientId
with the Auth0 client id, and wellKnownOpenIdConfiguration
with the OpenID configuration URL from Auth0.
We've also specified some scopes so that we can obtain profile and email information from the customer.
Now that the auth file is added to the app, we publish the app to Azure.
Note that we didn't put the client secret into the file. That's because we don't want to commit it to source control. Instead, we provide the app setting name (AUTH0_CLIENT_SECRET
) that we'll use to store that value in Azure.
Add a client secret app setting
In the function app's Configuration page, create an app setting named AUTH0_CLIENT_SECRET
. In the value, paste in the Auth0 client secret.
Enable file-based auth configuration
The last step we have to take is enable the use of our new file-based auth config. There's no UI for this yet. We can use an Azure CLI command to do it.
az rest --method put --url https://management.azure.com/subscriptions/$SUBSCRIPTION_ID/resourceGroups/$RESOURCE_GROUP_NAME/providers/Microsoft.Web/sites/$APP_NAME/config/authsettings?api-version=2018-02-01 --body "{\"properties\":{\"enabled\":\"true\",\"isAuthFromFile\":\"true\",\"authFilePath\":\"auth.json\"}}"
The above command updates the app's authsettings
properties with the following values:
enabled
= true
isAuthFromFile
= true
authFilePath
= auth.json
Test it out
Now when we try to access the function app in the browser, we're redirected to Auth0. We can create a new account to log in.
In an HTTP triggered function, the authenticated user's information can be obtained from the x-ms-client-principal
header. We need to convert it from base64 encoded JSON.
module.exports = async function (context, req) {
const buffer = Buffer.from(req.headers["x-ms-client-principal"], "base64");
const user = JSON.parse(buffer.toString("ascii"));
const email = user.claims.find(c => c.typ === "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress").val;
const nickname = user.claims.find(c => c.typ === "nickname").val;
context.res = {
status: 200,
body: `Hello ${nickname} [${email}]`
};
};
This function returns:
Hello anthony [anthony@anthonychu.ca]
Resources
Azure Functions and Azure App Service recently added integration with OpenID Connect (OIDC) providers. We can now use any OpenId Connect compliant provider to authenticate users in our apps.
In this article, we'll look at how to configure Auth0 with Azure Functions. The same steps can be used to configure any other OIDC provider and can also be applied to Azure App Service.
Overview
To integrate an OpenID Connect provider with Azure Functions, we need to follow these steps:
- Obtain a client id and secret plus other config settings from the OIDC provider.
- Create an authentication config file in our app and add the relevant information from the OIDC provider to the file.
- Supply the client secret in an app setting.
- Enable file-based authentication configuration in the app.
Create an app in Auth0
Auth0 is a popular identity service. It supports login via many social identities as well as with app-specific accounts.
Instead of configuring our function app with social logins like Google or creating a custom username/password database solution, we can rely on Auth0 to manage all that for us and we simply integrate our app with Auth0 using OpenID Connect.
The first thing we need to do to get started is create a free Auth0 account. Then we create an app in Auth0 of type "Regular Web Application".
When the app is created, note the client id and secret.
Note: We need to create a function app in Azure before proceeding with the following steps. Auth0 is going to need to use the app name in some configurations.
In the Application URIs section, fill in these settings:
- Application Login URI -
https://<app-name>.azurewebsites.net/.auth/login/auth0
- Allowed Callback URLs -
https://<app-name>.azurewebsites.net/.auth/login/auth0/callback
- Allowed Logout URLs -
https://<app-name>.azurewebsites.net/.auth/logout
The most important setting is the Allowed Callback URLs, which tells Auth0 about the callback URL that the function app authentication will use.
Note that each URL has a segment with the value auth0
. This needs to match the name we give the OIDC provider in the configuration file that we'll cover next.
Click Save Changes. Then click on the subtle Show Advanced Settings link.
In the Endpoints tab, note the OpenID Configuration URL.
Create an authentication config file
Currently, OpenID Connect providers can only be enabled in Azure Functions or App Service using a new file-based configuration. Multiple providers can be configured in the same app.
The config file must be located in the root of the function app. We'll create one named auth.json.
Then we place this content in the file:
{
"platform": {
"enabled": true
},
"globalValidation": {
"redirectToProvider": "auth0",
"unauthenticatedClientAction": "RedirectToLoginPage"
},
"identityProviders": {
"openIdConnectProviders": {
"auth0": {
"registration": {
"clientId": "<auth0_client_id>",
"clientCredential": {
"secretSettingName": "AUTH0_CLIENT_SECRET"
},
"openIdConnectConfiguration": {
"wellKnownOpenIdConfiguration": "https://<auth0_tenant_name>.auth0.com/.well-known/openid-configuration"
}
},
"login": {
"nameClaimType": "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name",
"scope": [ "openid", "profile", "email" ],
"loginParameterNames": []
}
}
}
},
"login": {
"tokenStore": {
"enabled": true
}
}
}
Replace the values of clientId
with the Auth0 client id, and wellKnownOpenIdConfiguration
with the OpenID configuration URL from Auth0.
We've also specified some scopes so that we can obtain profile and email information from the customer.
Now that the auth file is added to the app, we publish the app to Azure.
Note that we didn't put the client secret into the file. That's because we don't want to commit it to source control. Instead, we provide the app setting name (AUTH0_CLIENT_SECRET
) that we'll use to store that value in Azure.
Add a client secret app setting
In the function app's Configuration page, create an app setting named AUTH0_CLIENT_SECRET
. In the value, paste in the Auth0 client secret.
Enable file-based auth configuration
The last step we have to take is enable the use of our new file-based auth config. There's no UI for this yet. We can use an Azure CLI command to do it.
az rest --method put --url https://management.azure.com/subscriptions/$SUBSCRIPTION_ID/resourceGroups/$RESOURCE_GROUP_NAME/providers/Microsoft.Web/sites/$APP_NAME/config/authsettings?api-version=2018-02-01 --body "{\"properties\":{\"enabled\":\"true\",\"isAuthFromFile\":\"true\",\"authFilePath\":\"auth.json\"}}"
The above command updates the app's authsettings
properties with the following values:
enabled
=true
isAuthFromFile
=true
authFilePath
=auth.json
Test it out
Now when we try to access the function app in the browser, we're redirected to Auth0. We can create a new account to log in.
In an HTTP triggered function, the authenticated user's information can be obtained from the x-ms-client-principal
header. We need to convert it from base64 encoded JSON.
module.exports = async function (context, req) {
const buffer = Buffer.from(req.headers["x-ms-client-principal"], "base64");
const user = JSON.parse(buffer.toString("ascii"));
const email = user.claims.find(c => c.typ === "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress").val;
const nickname = user.claims.find(c => c.typ === "nickname").val;
context.res = {
status: 200,
body: `Hello ${nickname} [${email}]`
};
};
This function returns:
Hello anthony [anthony@anthonychu.ca]