Azure Functions Security and Authentication

Securing Azure Functions means controlling who can call the function and what the function is allowed to access. A function that is publicly exposed without proper security can be abused, overloaded, or used to steal data. This topic covers the key security layers available in Azure Functions.

Security Layers in Azure Functions

┌──────────────────────────────────────────────────────────────┐
│             SECURITY LAYERS                                  │
│                                                              │
│  Layer 1: Function Keys (API Keys)                           │
│  └── Basic protection. Caller must include a key.            │
│                                                              │
│  Layer 2: Azure Active Directory (AAD) Authentication        │
│  └── Identity-based. Caller must prove who they are.         │
│                                                              │
│  Layer 3: Network Restrictions                               │
│  └── Allow only specific IP addresses or VNets.              │
│                                                              │
│  Layer 4: Managed Identity                                   │
│  └── Function authenticates to other Azure services          │
│       without storing passwords anywhere.                    │
│                                                              │
│  Layer 5: HTTPS Only                                         │
│  └── Block all HTTP traffic, allow only encrypted HTTPS.     │
└──────────────────────────────────────────────────────────────┘

Layer 1 – Function Keys (API Keys)

Function keys are simple secret strings that a caller must include in every request. Azure Functions generates these keys automatically.

Key Types

Key TypeScopeWhen to Use
Function KeyOne specific function onlyGive different callers access to specific functions
Host KeyAll functions in the appGive one caller access to all functions in the app
Master KeyAll functions + admin APIsAdmin operations only. Never share externally.

Sending the Key in a Request

# Option 1: Query string parameter
GET https://myapp.azurewebsites.net/api/GetOrder?code=abc123key&orderId=5

# Option 2: Request header (more secure — key not visible in logs)
GET https://myapp.azurewebsites.net/api/GetOrder?orderId=5
x-functions-key: abc123key

authLevel Values in function.json

authLevelKey Required?Which Key
anonymousNoNone
functionYesFunction key or host key or master key
adminYesMaster key only

Layer 2 – Azure Active Directory Authentication

Function keys provide basic protection but do not verify identity. Azure Active Directory (AAD) — now called Microsoft Entra ID — provides identity-based authentication. The caller must log in with a valid Azure account and receive a token before calling the function.

┌──────────────────────────────────────────────────────────────┐
│             AAD AUTHENTICATION FLOW                          │
│                                                              │
│  1. Caller logs in with Azure AD account                     │
│       │                                                      │
│       ▼                                                      │
│  2. Azure AD validates credentials                           │
│       │                                                      │
│       ▼                                                      │
│  3. Azure AD issues a JWT token (valid for ~1 hour)          │
│       │                                                      │
│       ▼                                                      │
│  4. Caller sends request with token in Authorization header  │
│     Authorization: Bearer eyJhbGciOiJ...                     │
│       │                                                      │
│       ▼                                                      │
│  5. Azure Functions validates the token                      │
│       │                                                      │
│       ├── Valid token → Function runs ✓                      │
│       └── Invalid / expired token → 401 Unauthorized ✗       │
└──────────────────────────────────────────────────────────────┘

Enabling AAD Authentication

Enable authentication through Azure Portal → Function App → Authentication → Add Provider → Microsoft.

After enabling, functions automatically reject requests without a valid Azure AD token. No code change is required in the function itself.

Reading User Identity in Function Code

module.exports = async function (context, req) {

    // Azure injects the caller's identity after successful authentication
    const user = req.headers["x-ms-client-principal"];

    if (user) {
        // Decode the base64-encoded identity
        const decoded = Buffer.from(user, "base64").toString();
        const identity = JSON.parse(decoded);

        context.log(`Called by: ${identity.userDetails}`);
        context.log(`User roles: ${identity.userRoles}`);
    }

    context.res = {
        status: 200,
        body: { message: "Authenticated successfully" }
    };
};

Layer 3 – Network Restrictions

Network restrictions limit which IP addresses or virtual networks can reach the function app. All other IPs are blocked at the network level before any code runs.

IP-Based Restriction

┌──────────────────────────────────────────────────────────────┐
│             IP RESTRICTION                                   │
│                                                              │
│  Allowed IPs:                                                │
│  ├── 203.0.113.10  (Office IP) → Allowed ✓                   │
│  ├── 10.0.0.0/24  (VPN range) → Allowed ✓                   │
│  └── All others               → Blocked ✗                   │
│                                                              │
│  Set in: Azure Portal → Function App →                       │
│           Networking → Access Restrictions                   │
└──────────────────────────────────────────────────────────────┘

Layer 4 – Managed Identity

Managed Identity solves a common security problem: how does a function authenticate to another Azure service (like a database or Key Vault) without storing a password?

With Managed Identity, Azure automatically provides the function with an identity. The function uses this identity to request access tokens. No passwords, no connection strings with credentials.

┌──────────────────────────────────────────────────────────────┐
│             MANAGED IDENTITY FLOW                            │
│                                                              │
│  Without Managed Identity:                                   │
│  Function → Stores DB_PASSWORD in settings → Connects to DB  │
│  Risk: Password can be leaked or stolen                      │
│                                                              │
│  With Managed Identity:                                      │
│  Function → "I am MyFunctionApp" → Azure AD verifies         │
│  Azure AD → Issues token → Function uses token               │
│  No password stored anywhere                                 │
│                                                              │
│  Steps:                                                      │
│  1. Enable System-Assigned Managed Identity on Function App  │
│  2. Grant the identity access to the target service          │
│  3. Function code requests a token and uses it               │
└──────────────────────────────────────────────────────────────┘

Enabling Managed Identity – Azure CLI

# Enable system-assigned managed identity
az functionapp identity assign \
  --name MyFunctionApp \
  --resource-group MyResourceGroup

# Output shows the principalId (the identity's object ID)

Using Managed Identity to Access Key Vault

const { DefaultAzureCredential } = require("@azure/identity");
const { SecretClient } = require("@azure/keyvault-secrets");

module.exports = async function (context, req) {

    // DefaultAzureCredential uses Managed Identity automatically in Azure
    // Falls back to local developer login during local development
    const credential = new DefaultAzureCredential();

    const vaultUrl = "https://mykeyvault.vault.azure.net/";
    const client = new SecretClient(vaultUrl, credential);

    // Get a secret from Key Vault — no password needed!
    const secret = await client.getSecret("DatabasePassword");
    context.log("Secret retrieved successfully");

    // Use the secret value
    const dbPassword = secret.value;
};

Layer 5 – HTTPS Only

Enable HTTPS-only mode to reject all unencrypted HTTP requests. This prevents credentials and data from being transmitted in plain text.

# Enable HTTPS-only via Azure CLI
az functionapp update \
  --name MyFunctionApp \
  --resource-group MyResourceGroup \
  --https-only true

CORS Security

Only allow specific origins to call the function from a browser. Open CORS (allowing all origins with *) means any website can call the function, which is a security risk for authenticated endpoints.

# Good: Allow only the specific frontend domain
Allowed Origins: https://www.mystore.com

# Bad: Allow everyone (OK for fully public APIs only)
Allowed Origins: *

Security Checklist

CheckStatus
Use function or admin authLevel for sensitive endpoints✓ Must have
Enable AAD authentication for user-facing APIs✓ Recommended
Enable HTTPS-only mode✓ Must have
Store secrets in Key Vault, not App Settings✓ For production
Use Managed Identity to connect to Azure services✓ Best practice
Restrict CORS to known origins✓ For authenticated APIs
Never log sensitive data (passwords, tokens, keys)✓ Always
Add local.settings.json to .gitignore✓ Day one requirement

Leave a Comment