I have an Azure Function ("version": "[4.0.0, 5.0.0)"
) written in Typescript and I'm trying to get EasyAuth to work.
I have 2 functions: exec()
and login()
. exec()
has function
level authentication set, and login()
has anonymous
level authentication set.
Both work as expected with exec()
returning a 401
error, and login()
returning a 200
success response.
When testing in Postman, if I add the host level default
function key in the Url using the ?code=<key>
the exec()
method authenticates correctly, and I get a 200
success response (as expected).
However, I want to use the header option to authenticate, and have added the x-functions-key
header tag, using the same host-level function key that was used in the URL parameter test. I also want to pass in an additional name/value pair in the header and access that within the function too. The steps I follow are consistent with this tutorial:
http://dontcodetired.com/blog/post/Azure-HTTP-Function-Authorization-with-Function-Keys
and
https://damienbod.com/2020/08/17/securing-azure-functions-using-api-keys/
I've even created a new custom key with the same results as above (both successful URL parameter test and failed header x-functions-key
test).
I suspect the header is being filtered out before it reaches the Azure Function. To test this, I make the same header-based call to login()
and write the context and request objects to context.log
:
2023-08-22T20:06:47Z [Information] Request!!!! HttpRequest { query: URLSearchParams {}, params: {} }
2023-08-22T20:06:47Z [Information] context!!!! InvocationContext {
invocationId: 'f05f6245-b681-4aad-bff6-60fcbe3b68de',
functionName: 'login',
extraInputs: InvocationContextExtraInputs {},
extraOutputs: InvocationContextExtraOutputs {},
retryContext: undefined,
traceContext: {
traceParent: '00-c92a4b542b0bb1a0e4635361dfc636ff-703d73ec197fc2e1-00',
traceState: '',
attributes: {}
},
triggerMetadata: undefined,
options: {
trigger: {
authLevel: 'anonymous',
methods: [Array],
route: undefined,
type: 'httpTrigger',
name: 'httpTrigger3',
direction: 'in'
},
return: { type: 'http', name: '$return', direction: 'out' },
extraInputs: [],
extraOutputs: []
}
}
2023-08-22T20:06:47Z [Information] Executed 'Functions.login' (Succeeded, Id=f05f6245-b681-4aad-bff6-60fcbe3b68de, Duration=66ms)
In this output, I would expect to see the x-functions-key
and my other hello
/world
header value in the above output.
I did find an article describing what might be a solution:
I've added the Access-Control-Expose-Headers
to my host.json and redeployed but it made no difference. E.g.:
"extensions": {
"http": {
"customHeaders": {
"Access-Control-Expose-Headers": "*"
}
}
}
Why isn't Azure Function EasyAuth working with the x-functions-key
(where it works with the URL parameter option)?
... and why aren't the header
values coming through to the login()
function at all?
------ UPDATE -------
OK, I've got my non x-functions-key
header coming through now. I discovered (using Typescripts auto-complete function in VS Code) that there are additional members that you can interrogate from the request):
context.log('Request.headers', request.headers);
Produces the following output:
2023-08-22T22:48:07Z [Information] Request.headers HeadersList {
cookies: null,
[Symbol(headers map)]: Map(24) {
'accept' => { name: 'accept', value: '*/*' },
'host' => { name: 'host', value: 'fxa-sitemap40-dev-eas.azurewebsites.net' },
'max-forwards' => { name: 'max-forwards', value: '8' },
'user-agent' => { name: 'user-agent', value: 'PostmanRuntime/7.32.3' },
'traceparent' => {
name: 'traceparent',
value: '00-4ef804db4293ee5ddc9810ed3b690143-b390f556c4d90053-00'
},
'aiden-test' => { name: 'aiden-test', value: 'hoihoi' },
'postman-token' => {
name: 'postman-token',
value: '23456f99-8979-4ee4-860e-f1a4cba067cf'
},
'x-arr-log-id' => {
name: 'x-arr-log-id',
value: '87e6b362-02d7-4b9b-87bb-a91e57601d52'
},
'client-ip' => { name: 'client-ip', value: '10.0.32.9:61024' },
'x-site-deployment-id' => { name: 'x-site-deployment-id', value: 'fxa-sitemap40-dev-eas' },
'was-default-hostname' => {
name: 'was-default-hostname',
value: 'fxa-xxxxxxxx-dev-eas.azurewebsites.net'
},
'x-forwarded-proto' => { name: 'x-forwarded-proto', value: 'https' },
'x-appservice-proto' => { name: 'x-appservice-proto', value: 'https' },
'x-arr-ssl' => {
name: 'x-arr-ssl',
value: '2048|256|CN=Microsoft Azure TLS Issuing CA 01, O=Microsoft Corporation, C=US|CN=*.azurewebsites.net, O=Microsoft Corporation, L=Redmond, S=WA, C=US'
},
'x-forwarded-tlsversion' => { name: 'x-forwarded-tlsversion', value: '1.2' },
'x-forwarded-for' => {
name: 'x-forwarded-for',
value: '1.145.212.27:2907, 13.75.34.193:29415'
},
'x-original-url' => { name: 'x-original-url', value: '/api/login' },
'x-waws-unencoded-url' => { name: 'x-waws-unencoded-url', value: '/api/login' },
'x-ms-original-url' => {
name: 'x-ms-original-url',
value: 'https://xxx.yyyy.app/api/login'
},
'x-ms-request-id' => {
name: 'x-ms-request-id',
value: '87e6b362-02d7-4b9b-87bb-a91e57601d52'
},
'x-ms-auth-token' => {
name: 'x-ms-auth-token',
value: 'Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6IasdfasdfasdfggfhasdfasdfEREMkQxNzg2RTIwNTVBMkY5NjYxMUEiLCJ0eXAiOiJKV1QifQ.eyJwcm4iOksrebjzYkE9PSIsInN1YiI6ImFub255bW91cyIsImlzcyI6Imh0dHBzOi8vYmx1ZS13YXZlLTA3MjBkM2UwMC4zLmF6dXJlc3RhdGljYXBwcy5uZXQvLmF1dGgiLCJhdWQiOiJodHRwczovL2Z4YS1zaXRlbWFwNDAtZGV2LWVhcy5henVyZXdlYnNpdGVzLm5ldCIsIm5iZiI6MTY5Mjc0NDQ4NiwiZXhwIjoxNjkyNzQ0Nzg2LCJpYXQiOjE2OTI3NDQ0ODZ9.KYE8fpMxws_ZqEdTL1l459yjy8RQ0LlhKQJI9SdUJhaB2HnW9NLsBWJKkLzA2f66k0uMQ7YEabekFaoDAfyKDwvDkF2vSnTj7wGKaMM6BiOFTAs1tgTfrgz8IlwEfhzl9fcMA208oefNkDpvRyNufLeVGr_NKtlfEKRm1w7gIm24pD5fiuLkQIBvtDJov2ow7RPAXDkQa7V2Xf5CAcOlE27qz2WQVtEL76HEIFb6z07O2HZg8Q99SuLdna0QLpnn1pk85W2eVkJVTbGjjkf5k_t3K8Fy6e5uu9knDKNud5_prr4zJ3hLmUW7Gsxhruz8OY_DjiPfN02VV4a14NX5yQ'
},
'disguised-host' => {
name: 'disguised-host',
value: 'fxa-xxxxxx-dev-eas.azurewebsites.net'
},
'x-ms-client-principal-id' => { name: 'x-ms-client-principal-id', value: 'anonymous' },
'x-ms-client-principal-idp' => { name: 'x-ms-client-principal-idp', value: 'azureStaticWebApps' }
},
[Symbol(headers map sorted)]: null
}
I see that it as an x-ms-auth-token
that I suspect is what's being substituted for the x-functions-key
somehow. I will start investigating that.
OK, I didn't think it was relevant to mention (but it is). I have the Functions attached to an Azure Static Web App (SWA). As indicated in this page's post:
https://learn.microsoft.com/en-au/azure/static-web-apps/functions-bring-your-own
See:
The authentication configuration by the SWA provides a redirect layer above the function app. This is modifying the header and exchanging it with the managed identities token in the x-ms-auth-token
value.
The information in the Function App's Authentication blade gave the hint on what to investigate further on:
As the instructions explain, you need to make the calls to the Function through the SWA to the API.