I was inspired to write this article because we rarely find React or Angular posts with .NET Core backend as examples, and I am sure, like me, there are several developers using this combination tech stack for their products.
Social Authentication being a very common use case, I felt was a good example to demonstrate how to structure such an app. This is a very opinionated (my way) of setting this code base.
If you wish to skip the post and get to the code, you can access it here https://github.com/mickeysden/dotnet-core-react-oauth-example (updated to .NET Core 3.1)
As mentioned in the post by Google, the following is the application flow we will be working towards:
Client: This is the client application, built in Reactjs (web) in our example
Server: This is the server backend that we will build using .NET Core 2
Google API Server and OAuth 2.0 Dialog: These are services build by Google that we will be using
Setup Google Developer Console
The first step is to setup API access for Google for you app (if you haven’t already done so). The steps are straightforward and documented in several posts. I like what @alexanderleon has posted in this article and I will simply provide a link to it.
Setup .NET Core Webapi backend
I am assuming that you have some experience with .NET Core WebApi. There are several tutorials out there, but you can get started here.
Basic steps I followed on Debian
- Step 1: Create a folder (in my case named backend) and change into the folder
- Step 2: Run command to create a new .NET Core WebApi project
$ dotnet new webapi
- Step 3: Add packages for Google.Apis.Auth, Newtonsoft.Json, Serilog (optional) and Serilog.Sinks.Console (optional)
$ dotnet add package Google.Apis.Auth
$ dotnet add package Newtonsoft.Json
$ dotnet add package Serilog
$ dotnet add package Serilog.Sinks.Console
Serilog is a great logging framework that provides a more flexible logging on top of the default .NET Core logging
- Step 4: Modify Program.cs as follows
As you will notice in the above code, a logged is activated at the start of the program, along with loading the contents of the appsettings.json file into a static object.
- Step 5: Modify Startup.cs as follows
The methods ConfigureServices and Configure have been modified to include Jwt Authentication to the web api.
- Step 6: Database — in the example I have not used a database but created a service (IAuthService.cs) to store data in memory. This can easily be modified to use a MySQL or MongoDb (or any other personal favorite data store) implementation.
You will notice in the Authenticate implementation I pass a GoogleJsonWebSignature object. More on this below.
- Step 7: Controller — this is where the business logic will flow through. As depicted on Step 4, in the Google auth image above, once the client gets a successful one-time token from Google, it will pass this token to the backend server that we are building. I have defined the endpoint for this to be https://<server-url>/v1/auth/google and here is the controller code for this.
As you see in the controller method above, a POST request is sent to the endpoint, where the payload consists of a JSON with the Google returned one-time tokenid attached.
Once the token is received, it is verified by the backend server by calling GoogleJsonWebSignature.ValidateAsync method from the Google Auth API. Once validated, this is then internally authenticated to find if the user exists, and if not create it. This all happens in the AuthService implementation described above.
Once a user object is created, it is used to return a JWT token back to the client for future bearer authentication with the backend server.
Setup React frontend with Redux and React-Router
The frontend is created using the create-react-app tool.
$ create-react-app frontend && cd frontend
$ npm install react-google-login react-redux react-router-dom redux redux-logger redux-thunk jsonwebtoken
$ cd src
$ mkdir actions components containers reducers services
Follow these steps next:
- Step 1: Create authActions
The login action passes the token as a payload to the reducer, but the logout action doesn’t.
- Step 2: Create reducer
Upon login, we are simply storing the payload, which is the JWT returned from our server.
- Step 3: Create service to validate if token is active (this is needed to make sure the Bearer we have locally is active)
- Step 4: Update App.js to setup routing and call Login and Logout containers
As you will see, this is a bare bones react app with dummy components for Home, About and NotFound pages. These will be customized to your app (if you need them). The Login and Logout containers are where the authentication heavy lifting is happening.
You will also notice that I am using CSS items from the bootstrap framework. I have not called these out, as this would ideally be dependent on the layout of your application.
- Step 5: Implement Login.js
As you see, the code checks if the user is authenticated, if not, we send it to google servers to do so. Once authenticated from the Google servers, the token received is sent to our callback server we created above. Once we get a successful token from our server, the login action is dispatched and redux takes over.
Keep in mind to use the withRouter method by React-Router v4. This smoothed things with Redux.
- Step 6: Implement Logout.js
Logout is simpler than login. The inbuilt componentWillMount() is called to dispatch a logout on redux.
- Step 7: Tie it all together
Finally, everything is tied up in index.js initializing the redux store and then calling Router.
Hopefully this post and the code gave you an idea of how a .NET Core WebApi server can be used as backend for a React app, specially in the case of social authentication. Please let me know your thoughts on reading and any coding experiences you have on this.