Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Implementing authentication and authorization with React hooks, .NET Core Web API, and SQL Server

I have an application that I have built using React hooks, a SQL Server database, and a .NET Core 3.1 Web API. I'm really struggling to understand the relationships of the all the moving parts. I want to avoid reinventing the wheel and leverage existing libraries and frameworks. JWT seems like the way to go here from what I've learned and it just gets a bit confusing. Here are my requirements:

  1. Create account and log in/out with a custom site account OR use Google/Facebook/Microsoft/etc. (I can start with one or the other but don't want to box myself in and rewrite a ton of stuff to add the other)
  2. Leverage .NET Core Identity in the existing project to handle users, roles, etc. in the SQL Server database.
  3. Use React hooks pattern (I can limp my way through translating class components if I must)

I think I'm getting lost in all of the decoupling (which normally is a good thing!) I see articles about React with dummy back ends and I get lost. I see posts about .NET Core and can't figure out how to use it with React. Conceptually most of it makes sense, but I haven't found a place that helps me understand what the code should look like start to finish.

SO HERE ARE MY QUESTIONS!

  1. Are the React front end application and the React auth service the same thing? Can they be? Must they be?
  2. Is the JWT string generated on the React side or the .NET side? Best library for that?
  3. How (or does?) MS Identity Server fit into this equation?
  4. I don't full understand the concept of the refresh token despite looking at about 100 articles. Is a refresh token 100% necessary? Benefits/drawbacks to using/not using them?

It's a lot to sort through and I'm just hoping someone can help me simplify.

like image 630
mateoc15 Avatar asked Jan 31 '21 16:01

mateoc15


2 Answers

  1. The part in the React app that would handle the authentication should naturally be a component, which would then be imported by other parts of the app (e.g, by a login component). You can see an example tutorial here.

  2. The JWT is generated on the server side, which is .NET Core in your case. It must be created on the server side, because generating it on the client side implies having the secret in there, so that an attacker may steal it and create valid tokens. See also this answer.
    As for generating it: You can generate it by yourself, or just use an authentication framework (e.g., IdentityServer4) or a 3rd-party authentication (e.g., using Google login) so that it will be generated for you. If you do decide to generate it yourself, I don't think you need complicated things (and by that I mean, you don't even need libraries like JWT.NET). Just use a simple tutorial, like this one.

  3. IdentityServer4 is an authentication framework, which implements the OpenID Connect and OAuth 2.0 protocols, and uses JWT auth by default.
    Using it will get you the authentication behavior, including for example login and logout (it actually comes with its own login pages (Login.cshtml, Logout.cshtml)), but not registration.
    It is recommended to use it for that purpose alone, and you can advise the following two answers to understand better the separation of concerns when dealing with authentication (although the questions' titles refer to user creation, the answers specifically address authentication as well):

    • User Registration Process with IdentityServer4
    • Store user data in auth server or resource server? Or both?
  4. If you want to add more security to your app, you will have an exp claim in your JWT. And if you have an exp claim and don't want legible users to have to re-login every time their JWT expired, you'll have refresh tokens. You use a refresh token to get a fresh new access token. If you'll use IdentityServer4, refresh tokens are already implemented for you, though you'll have to configure them explicitly. Advise the following sources:

    • IdentityServer4 refresh tokens documentation.
    • A complete tutorial that also explains how to use refresh tokens.

    Also, I don't know what those 100 articles you read were :) but I think the following SO posts are great:

    • Is a Refresh Token really necessary when using JWT token authentication?.
    • JWT refresh token flow.
    • What goes into a JWT refresh_token?
like image 73
OfirD Avatar answered Oct 12 '22 18:10

OfirD


This question is far too generic to add a simple answer. Also answering your numbered questions most likely will not help you to move forward with your project. Therefore I'm trying to provide a generic answer here.

Account creation

As you have a backend with a DB the accounts must be created on the server. So you capture the username and password in your react app then send this data to a registration endpoint of your backend. Note you might want to hash the password before sending for security reasons and most likely it will be stored on this way in the DB anyway. Your backend can do validations at this point by using the submitted data (e.g. validate already taken username, etc). If the details are valid then you store the details in your DB. This is the point where you can also hook up with MS IS if that's a requirement. When the account details are stored you can generate a token using JWT or any other libs. This token is saved on the server and returned in the response of the initial register request. Optionally a refresh token can also be returned here.

Token Handling

The registration request should return an auth token as described above in case of successful registration. This auth token (and the optional refresh token) should be stored on the client side (e.g. react context or if you are using some state management lib like redux then you can set it there in the global state).

If you would like to use "remember me" then the stored token should be persisted at client side.

At this stage your user is logged in. From now on you will send this token in the header of all requests to your backend. Then your backend can look up the received token with the one stored in your DB and decide whether the current request is allowed.

Token refresh

For security reasons you may want to set a TTL for all the tokens issued. I.e. invalidate the tokens after a certain amount of time. When a request using an expired token comes in to your backend then you return an expired response what should be processed on the client side. The client should make a refresh token call by using the locally stored refresh token. This should generate a new auth token on the server and replace the old token with the freshly generated one.

You can set the TTL to "keep forever" in which case you will not need to deal with token refresh.

Login

Your react app captures the user/password and send it to your backend on the same way as in case of registration. The backend validates the account details and generates and returns a new token. Then your client should use this token on the same way as described above at registration.

There are millions of other details what can be addressed here but probably it is enough for you to start with.

like image 45
Zoltan Magyar Avatar answered Oct 12 '22 18:10

Zoltan Magyar