Building and Securing Web APIs with ASP.NET Core 3.0

Learn how to build a web API with ASP.NET Core 3.0 as well as how to secure this API with Auth0’s robust authentication and authorization features.

Read on :hammer_and_wrench:

Brought to you by @andrea.chiarelli :man_technologist:t2:

1 Like

Hi there, please reach out to me for any comment and/or issue.
Have a good reading!


Excellent explanation, thank you. One question–how does the calling app get the token at runtime? In your walk-though you have the user visit the Auth0 site and get a test token.

Hi @tregan3,
Thanks for appreciating the article :slight_smile:
The way a client gets the access token depends on the type of the client itself. You have different flows if your client is a Web application, a SPA, a mobile app, and so on.
You can take a look at the Auth0 official documentation for more information.
If you want to see some code and your client is a Single Page Application, you can take a look at the quickstarts here
Let me know if need more help.

Hi Andrea, are there any updates to how scope validation would work in .NET Core 3.0 compared to how it was done in the 2.0 quick start at ASP.NET Core Web API v2.0: Authorization ?

It would be good to see an example of scoped authorizations in this example as well, such as decorating with [Authorize(“read:messages”)]. Thanks for all the great info!

Thank you!


Hi Andrea, thanks for the article!

And agree with we need to get more details, since quick start at quick start ASP .Net Core v 2.0 isn’t applicable for .Net Core 3.0.

I’ve just tried to migrate a workable solution with Auth0 to .Net Core 3.0 - and seems like authorization doesn’t work at all. I use such attributes like [Authorize(Auth0Configuration.WRITE_PERMISSION)] with HasScopeRequirement, AuthorizationHandler and IAuthorizationHandler.

That would be great if you create one more comprehensive guide for .Net Core 3.0 Web API + Auth0



Hi and @reshifa,
Thank you very much for your feedback. I’m going to plan a tutorial on this topic soon.
Stay tuned!


Thanks a lot @andrea.chiarelli for catching that feedback!


I’ve really enjoyed this tutorial! I’m new to auth0 and I’ve hit a roadblock at the very end of your tutorial. I’ve tried this in my code and also after cloning your git. I keep getting a 500 error when I try to post to the api using my token. I’m thinking I’ve messed up the syntax of either my auth0 domain or how I’ved added the token. Here’s a code snippet from my appsettings.json:

{ "Logging": { "LogLevel": { "Default": "Information", "Microsoft": "Warning", "Microsoft.Hosting.Lifetime": "Information" } }, "AllowedHosts": "*", "Auth0": { "Domain": "", "Audience": "" } }

Does that look alright? Also, is this how I’m supposed to format the post:

curl --insecure
–request POST
–url https://localhost:5001/api/glossary
–header ‘content-type: application/json’
–header ‘authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6IlJEZERNRFpFTXpNek1ERkNORGd4TVRBME9ESXlNVUZGUkRJeE1EQTFORGxFTlVJeVFqTkJNdyJ9.eyJpc3MiOiJodHRwczovL2Rldi01OXRtOWNhaC5hdXRoMC5jb20vIiwic3ViIjoiNlpVaVh5UnpRTzNvejlTYk9lcE1KVVVFc2RCUWtreE1AY2xpZW50cyIsImF1ZCI6Imh0dHBzOi8vZ2xvc3NhcnkuY29tIiwiaWF0IjoxNTczMjY1NzQ5LCJleHAiOjE1NzMzNTIxNDksImF6cCI6IjZaVWlYeVJ6UU8zb3o5U2JPZXBNSlVVRXNkQlFra3hNIiwiZ3R5IjoiY2xpZW50LWNyZWRlbnRpYWxzIn0.PAvK9yOYmeHdlx4Aoidlf83Sh_EXnhJlXn-d1I4TYUdKoLSPmO3N-HEjX_-umAm2S9pYKT9uuNxXaKVk7CKfwT_9-Aq5NDkIfOGGfFJSID_iE6PWBPnqfUw0ja1r9KzTpQas41GVGZ8NSiQX-KgNoQctBP4lhCxjIoyzvghT2XMfn3QeJUr_Y8ZYyVT3aUAuVp0TVRIeQCXH7ZMRbpLMbrq18uFy2dBbn0f2nfpWdJWfnBnAJOkEKZ2FUFpb2Gsm8YWnkza-F4QhMgch6za-Hw9Br1xGWxUHBgQ0RVElfj7QnKm5hMnKXkV5edTMkN4l1ILpR7VSxAuvucd-oCb8CA’
–data ‘{ “term”: “MFA”, “definition”: “An authentication process that considers multiple factors.”}’

It would also be helpful if you could explain how I could use postman in lieu of the terminal for this. Thanks!

Hey, thank you for reading my tutorial.
I’m afraid that you are getting that error because of the value of the Domain key in the appsettings.json file. You provided a URL, but it should be just a domain. In your case, you should just assign, without https://.
Try with this change and let me know.

If you want to use Postman instead of cUrl, you should simply map those parameters to the corresponding UI fields. For example, the following picture shows how you should insert the Authorization header

You should also provide the Content-Type header:

And the body:

I hope this can help you in completing your journey with Auth0.

Thanks! Worked great


Super glad to hear that @joshisplutar!

Thanks for the example. I implemented all the steps prior to OAuth and I can test GET/POST/PUT/DELETE with postman successfully.

However, cUrl only works for GET. For POST and PUT examples it returns “title”:“Unsupported Media Type”,“status”:415. I also needed to change the url to the local port 44320, not 5001 as in examples. Is there something wrong with my setup?

Hey there @doingnz!

I’m sure this blog article author @andrea.chiarelli will look at that once he’s online!

Hi @doingnz,
Thank you for reading the tutorial. I’ll try to give you my feedback to help you understand the possible cause of the issues.
If all is working fine with Postman, I’m quite sure that your Web API is OK. So, the issue should be with the client (cUrl) or with the environment.

The 415 status code says that the API expects a specific data type (application/json in our case) but you are sending a different one. Be sure to include the --header 'content-type: application/json' flag in the cUrl command.
Check this and let me know if it helped.

In addition, why did you need to change the default port? Which error message did you receive? Was the 5001 port in use? Do you have a firewall that may block cUrl’s activity?
Also, the operating system you are using may help me to find a possible cause of your problems.
If you can give me more information, I will try to figure out what’s going on.


Thank you for offer to help.

I finally realised the issue with the port is my debugging session in Visual Studio was directed to IIS Express. When I change it to the project’s assembly, then port 5001 works:

The 44320 port is in my launchSettings.json as follows :slight_smile:

  "$schema": "",
  "iisSettings": {
    "windowsAuthentication": false,
    "anonymousAuthentication": true,
    "iisExpress": {
      "applicationUrl": "http://localhost:61043",
      "sslPort": 44320
  "profiles": {
    "IIS Express": {
      "commandName": "IISExpress",
      "launchBrowser": true,
      "launchUrl": "api/glossary",
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development"
    "WebApplication7": {
      "commandName": "Project",
      "launchBrowser": true,
      "launchUrl": "api/glossary",
      "applicationUrl": "https://localhost:5001;http://localhost:5000",
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development"

Regarding curl 415 error. I am running it on Windows 10, with latest patches. Firewall off.
Yes I used the lines verbatim and include the header definition. Just ran the PUT test again as follows.
Tried to update to latest cUrl too.
Looks like curl gets confused when it is parsing the cmdline as it thinks term, JWT and definition are hosts. I have tried retyping all the " and ’ characters.

C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise>curl --insecure --request PUT --url https://localhost:5001/api/glossary --header 'content-type: application/json'  --data '{ "term": "JWT", "definition": "An open, industry standard RFC 7519 method for representing claims securely between two parties. Auth0 uses JWT format for ID Tokens."}'
{"type":"","title":"Unsupported Media Type","status":415,"traceId":"|2f09b40b-4753ea38bf3e6390."}curl: (6) Could not resolve host: application
curl: (6) Could not resolve host: term
curl: (6) Could not resolve host: JWT,
curl: (6) Could not resolve host: definition
curl: (3) [globbing] unmatched close brace/bracket in column 134

C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise>curl -V
curl 7.55.1 (Windows) libcurl/7.55.1 WinSSL
Release-Date: [unreleased]
Protocols: dict file ftp ftps http https imap imaps pop3 pop3s smtp smtps telnet tftp
Features: AsynchDNS IPv6 Largefile SSPI Kerberos SPNEGO NTLM SSL

C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise>

I have tried to guess a number of different other ways to reorder the cmd line or remove spaces, but curl is not happy and always returns 415.

Thanks for the details, @doingnz.
The 415 error seems to come from an issue with Windows’ cUrl.
I found a discussion on Stackoverflow where the user has the same problem and it seems to depend on nested quoting chars.
According to their suggestion, you should use the following syntax:

curl --insecure --request PUT --url https://localhost:5001/api/glossary --header "content-type: application/json" --data "{ \"term\": \"JWT\", \"definition\": \"An open, industry standard RFC 7519 method for representing claims securely between two parties. Auth0 uses JWT format for ID Tokens.\"}"

Currently, I haven’t a Windows machine at hand, so I haven’t had a chance to try it out.
Please, give a try and let me know if it helped.

The syntax you suggest with \" for the quote characters fixed the problem and cUrl now works as expected!

Thanks again for the examples and helping find a fix for cUrl.

1 Like

Outstanding article! I now have my API fully secured with a wide array of scopes and permissions.

I will say that I had to combine info from this article with info from the quickstart in the tutorial. And then to test it out, I used a machine-to-machine api token with all the scopes turned on.

Just wanted to say thanks for the instructions, and thanks for Auth0 itself.