Why does my HttpTrigger AuthorizationLevel.User keep return 401?

Sean Sparkman 10 Reputation points
2025-09-09T03:58:22.7866667+00:00

Why does my token work for /.auth/me but my custom HttpTrigger AuthorizationLevel.User not work. If I set the AuthorizationLevel.Anonymous, the endpoint works just fine, so it's the easy auth. I am using the idToken generated from logging in with google. JWT.IO also says that the JWT has an invalid signature. I have configured EasyAuth with Google Provider. I get past the google screens no problem.

https://<function>.azurewebsites.net/.auth/login/google =>
I pulled the authentication token from the token fragment in resulting callback.

I put the token in the X-ZUMO-AUTH header for /.auth/me => gets what looks valid

I call the custom HttpTrigger AuthorizationLevel.User with the same token => 401

Ultimately, I am planning on using this in a .NET Maui app using WebAuthenticator. I have that part all worked.

I have tried creating a whole new azure function, configuring and deploying it. No dice. I am at wits in, and I have been trying to fix this for multiple days. i am convinced that this is a configuration problem.

P.S. Allowed external redirect URLs cannot be set to anything besides https or http, so I can't make it open an app.

Azure Functions
Azure Functions
An Azure service that provides an event-driven serverless compute platform.
{count} votes

3 answers

Sort by: Most helpful
  1. Alex Burlachenko 18,485 Reputation points Volunteer Moderator
    2025-09-09T09:55:35.2266667+00:00

    the fact that .auth/me works but your function doesn't is a huge clue. the .auth/me endpoint just reads the encrypted cookie that easy auth sets, but your function is trying to validate the JWT token directly from the header. that's two different authentication mechanisms.

    when you use AuthorizationLevel.User in your function, it expects a valid JWT token in the Authorization header with the Bearer scheme. it doesn't use the X-ZUMO-AUTH header. that header is for the mobile client sdks.

    so, instead of putting your token in the X-ZUMO-AUTH header, try this. add an Authorization header with the value Bearer <your_id_token>. your function should then validate the signature of that JWT against the google issuer.

    but wait, you said JWT.IO says the signature is invalid. that's the real problem right there. if the signature is invalid, azure functions will reject it and return a 401. this usually means the JWT wasn't signed correctly, or the key used to sign it isn't available for validation.

    since you're using google, make sure you configured the client id and secret correctly in your easy auth settings. also, check that the token you're using is the id_token and not an access_token. easy auth and your function need the id token.

    this might help in other scenarios too, always use the id token for authentication.

    aha, and here's another thing. the Allowed external redirect URLs field in the google auth setup needs to include your function's callback url. it should be something like https://<your-function>.azurewebsites.net/.auth/login/google/callback. if that's missing, the token might not be issued correctly.

    also, give this microsoft doc a quick read. it explains how the tokens flow with easy auth. https://learn.microsoft.com/en-us/azure/app-service/overview-authentication-authorization

    hope this gets you past that 401 error. swapping that header should do the trick. let me know if it works.

    Best regards,

    Alex

    and "yes" if you would follow me at Q&A - personaly thx.
    P.S. If my answer help to you, please Accept my answer
    

    https://ctrlaltdel.blog/


  2. Sean Sparkman 10 Reputation points
    2025-09-09T21:29:33.6233333+00:00

    Logging in steps to reproduce:

    1. Open in chrome https://<function name>.azurewebsites.net/.auth/login/google
    2. Select my google account to login with
    3. Chrome shows me "You have successfully signed in" on the url: /.auth/login/done#token=<json object>
    4. Take the authenticationToken from the JSON Object (It starts with ey)
    5. Validate this token (Fails validation)
    6. Open Postman
    7. Create new request
      1. Url: /.auth/me
      2. Add header X-ZUMO-AUTH with authenticationToken from JSON Object
    8. Press Send
      1. Receive a 200 OK
    9. The response includes access_token, expiration, provider name, all of my google claims, user_id (my google address and outside of the claims array, and a different id token
    10. Create new request
      1. Url: /api/addresses/countries
      2. Add header X-ZUMO-AUTH with authenticationToken from JSON Object
    11. Press Send
      1. Receive a 401 Unauthorized
    12. Remove X-ZUMO-AUTH header from /api/addresses/countries
    13. Set the Authorization to Bearer and use the authenticationToken from the JSON Object
    14. Press Send
      1. Receive a 401 Unauthorized
    15. Take the authenticationToken from the JSON Object and Base64 the value as the Bearer Token
    16. Press Send
      1. Receive a 401 Unauthorized
    17. Take the AppServiceAuthSession cookie from Step 3 and replace the Bearer Token
    18. Press Send
      1. Receive a 401 Unauthorized
    19. Take the google id_token (different token altogether)
    20. Create new request
      1. Url: /.auth/login/google
      2. Body (json): { "id_token": "..." }
      3. Method: POST
    21. Press Send
      1. Receive a 200 OK
      2. Response Body: { "authenticationToken": "...", "user": { "userId": "sid:..." } }
    22. Validate this new authenticationToken (Fails, Invalid Signature)
    23. Create new request
      1. Url: /api/addresses/countries
      2. Add header X-ZUMO-AUTH with authenticationToken from /.auth/login/google results
    24. Press Send
      1. Receive a 401 Unauthorized
    25. Remove X-ZUMO-AUTH header from /api/addresses/countries
    26. Set the Authorization to Bearer and use the authenticationToken from /.auth/login/google results
    27. Press Send
      1. Receive a 401 Unauthorized
    28. Lose hair.
    0 comments No comments

  3. Sean Sparkman 10 Reputation points
    2025-09-17T03:23:32.5366667+00:00

    I fixed it by turning on auth all endpoints and setting all functions to AuthorizationLevel.Anonymous. This is super counter intuitive. I am seriously considering moving to a different solution. I will probably have to open a whole new issue, but the externalRedirectUrls broke today. It no longer works with myapp://easyauth.callback. The documentation gives the example of myapp://auth, but that doesn't past validation. I had myapp://easyauth.callback working today, but it stopped working. I am guessing some kind of update. Azure Functions Authentication is far from easy. I am not even sure why I am using it.

    0 comments No comments

Your answer

Answers can be marked as 'Accepted' by the question author and 'Recommended' by moderators, which helps users know the answer solved the author's problem.