sharmaaditya570191's Blog

Diving deep into Strapi to build the EOS feature request system in GSOC’20

sharmaaditya570191
Published: 06/22/2020

Hola a todos! Give me company as I explain to you the internals of Strapi and how I am using various mechanisms to implement custom and secure solutions for our feature request system. Grab your drink, sit back and relax as I walk you through the details.

What did I do this week?

Strapi is the magic behind our awesome applications at EOS. It is the leading open-source headless CMS. It’s 100% Javascript, fully customizable and developer-first.

This week I completed user authentication and authorization to our system. This includes register, login, logout, forgot password and reset password functionality. Lets have a look at how we can do this with Strapi and React.

Strapi exposes a plugin system where each plugin is like a small independent sub-application. It has its own business logic with dedicated models, controllers, services, middlewares or hooks. It can also have its own UI integrated in the admin panel.

I used the Roles and Permissions plugin to complete my tasks of the week. This plugin provides a way to protect our API with a full authentication process based on JWT. Each time an API request is sent, the server checks if an Authorization header is present and verifies if the user making the request has access to the resource. To do so, our JWT contains our user ID and we are able to match the group our user is in and at the end to know if the group allows access to the route.

The API response to the authentication route contains the user’s JWT in the jwt key. We will have to store this JWT in our application, it's important because you will have to use it the next requests.

We decided to store the JWT in a httpOnly cookie instead of the easy solution of storing it in localStorage which makes our application prone to XSS attacks. This means that we need to customize Strapi to set the jwt in the cookie instead of returning it in the API response. This will ensure that our front end application does not have to store sensitive data for future authenticated requests.

Strapi internally uses Koa.js , a new web framework designed by the team behind Express, which aims to be a smaller, more expressive, and more robust foundation for web applications and APIs. I quickly learnt basic syntax as I am already familiar with Node.js and Express .

Now every plugin in Strapi follows a fixed architecture and all installed plugins can be found in the node_modules folder with the naming convention of strapi-plugin-* .

To customize those installed plugins we can work in the /extensions directory. It contains all the plugins' customizable files. I customized the user-permissions plugin by modifying the Auth.js controller file to issue a JWT to the user and set it in a httpOnly cookie after all server side validations are done. I also changed the response by the controller to return a “status” key with “Authenticated” value instead of the token. This confirms that the user has been authenticated.

Wait! Strapi reads the token from the Authorization header in the API request so this won’t work for now. I further added a permissions.js file to the policies folder where I attach the token to the header after reading it from the cookie which was set earlier.

Policies in Strapi are functions which have the ability to execute specific logic on each request before it reaches the controller’s action. They are mostly used for securing business logic easily. Each route of the project can be associated to an array of policies.

Now to implement the logout functionality I set up a custom /logout route with a controller to set the token to null in the cookie. This destroys the user session safely in seconds.

Patience folks! Our user can forget his/her password too. I used sendgrid service to send email to users with a link which contains a URL param code which is required to reset user password.

I implemented the client side functionality including the requests to the API in a React custom hook named useAuth to finally complete the agile task.

What is coming up next?

This week I will implement the functionality to create a new request and read and display the existing feature requests along with all attributes like votes and comments in an engaging UI.

I will also try to setup providers which are currently broken due to an issue in Strapi v3.0.1 here.

Did I get stuck anywhere?

We all are bound to fall. Any great thing does not start perfect. At first I could not figure out how to manage the user state properly and tried using a reducer but the state reset itself to the initial one on page refresh. Finally I implemented the idea to read the state from localStorage without saving any sensitive information.

Strapi uses the sendmail service by default to send mails to the users but it was not working and was always returning a 400 status code. I added sendgrid service to overcome this problem.

All this hustle and bustle marked the end of my week with a mesmerizing annular solar eclipse on June 21, 2020. Stay tuned as we come up with some amazing features in the weeks ahead.

View Blog Post

Inside look of the EOS feature request system in GSOC’20

sharmaaditya570191
Published: 06/15/2020

Hello everyone! Come join me to catch a glimpse of how things work under the hood in the EOS feature request system. You can enjoy the magic which happens behind the scenes to hold back our pleasing and engaging UI, a fit for all devices.

What did I do this week?

This week my focus was to implement a main part of the server side so that I have with me the API endpoints to interact with our applications data via the user interface.

This includes working on a famous Node.js based open source headless CMS called Strapi. The best thing I learnt about Strapi is that I can customize it and add my own logic according to the needs of my application. Strapi internally uses Koa.js, a new web framework designed by the team behind Express, which aims to be a smaller, more expressive, and more robust foundation for web applications and APIs.

I built a new content type for our feature request system. A content type is the schema of the data structure. I added suitable fields to it after some discussion about the design of our application with our mentors.

I later added another new content type on the server side for the feature requests status labels. This allows admins to create custom status labels according to their organization workflow. These have a relation with the feature requests just like a user so that we can select a status while creating a feature request.

I also came up with a custom solution for user authentication but updated it later as it did not fulfill all user cases. I customized the JWT authentication by storing it in a httpOnly cookie as discussed with my mentors earlier. This included some custom code in Koa.js to override the default behaviour of Strapi.

What is coming up next?

I will work on adding various OAuth and OAuth2 providers to enable authentication in our application. Strapi supports all major providers like Github, Facebook, Twitter and Google.

Further I will also connect the remaining login and forgot password UI to my authentication logic.

Did I get stuck anywhere?

Strapi internally uses JWT for user authentication. It returns the JWT along with the user information when the user registers or logs in. I had to customize the users-permissions plugin using the extension mechanism in Strapi .

This ensures that our front end application does not have to store sensitive data such as JWT in client side local, session or cookie storage for future authenticated requests.

I am familiar with Express and after learning basic Koa syntax I was good to go. I was then able to write some custom code in Koa to override the default behaviour of the plugin.

This closed the week and helped me learn a lot about how Strapi works internally. Stay tuned for my next blog where I will explain in detail about how I implemented a custom and secure authentication with React on the client side.

View Blog Post

Laying out the foundations for the EOS feature request system in GSOC’20

sharmaaditya570191
Published: 06/08/2020

Hey folks! My goal is clear, the stage is set and I am ready to hit the keyboard to light up your way to the EOS feature request system which aims to provide users an accessible interface within EOS to request new features or icons.

What did I do this week?

The first task was to let users register or login to the system which means that I need to come up with the client side logic for user authentication to control if an incoming request can proceed or not.

The structure of our application is going to be a mix of public and private pages. We will have a public login page that will contain the login component to handle our authentication. We are going to be creating client only routes that are conditionally rendered using the @reach/router . The content in the private components is irrelevant for now but it’s important that the user must me logged in to access these routes.

Most of our authentication logic will be handled in a custom hook that I create which will be called useAuth and as the name implies will live inside the file useAuth.js in our hooks folder. This file will be utilizing the useReducer API to manage our user state throughout the application. I used a reducer to receive our user state object and update our state by dispatching actions.

First, I defined our DEFAULT_STATE which I am assuming is an unauthenticated user. I then created a reducer using the redux convention and switched our action.type so when I call a dispatcher function I can pass in the type of action we want to execute. I then defined various action types like REGISTER , LOGIN and LOGOUT .

For the server side implementation using Strapi, I have the user roles and permissions plugin installed at my disposal. The users and permissions role exposes a route located at http://localhost:1337/auth/local in which we can send a POST request with our users identity and password. The route will handle validation and upon successful authentication will return a jwt token to be used in further requests as well as a user object that contains information about our validated user.

I learnt that I can not user our admin username/password with this endpoint.

What is coming up next?

Devesh (my awesome GSOC partner) built an amazing responsive and engaging UI for registering users. I will connect my authentication logic with his UI to complete the feature on the client side.

On the server side I will be coming up with solutions to differentiate our database collections and routes for the EOS Design System and the EOS feature request system so that it is easy to identify them.

Did I get stuck anywhere?

Our EOS Strapi instance was running on a very old alpha version for which there was no support. My mentors did really nice work to update Strapi to the latest stable release.

Also Strapi uses JSON Web Tokens (JWT) internally for user authentication. Our team had a nice discussion on this with various ideas pouring in for the storage mechanism for the JWT which needs to be sent in an Authorization header with every request for making permission-restricted API requests.

We learnt that the JWT should not be stored in localStorage as an XSS attack can let an external attacker get access to the token.

We came up with two solutions for the storage of JWT :-

  1. React state or memory with the only downfall that if a user refreshes the page that state is gone but we can get a new token on refresh too.
  2. httpOnly cookie which is a special kind of cookie that’s only sent in HTTP requests to the server, and it’s never accessible (both for reading or writing) from JavaScript running in the browser.

This closed the week along with some rainfall and rainbows by our healing nature. Keep calm and stay tuned as the next batch of some amazing functionality gets loaded to our feature request system :)

View Blog Post

First check-in to GSOC’20 @ Python Software Foundation

sharmaaditya570191
Published: 06/01/2020

Hello! I am Aditya Sharma, a second year Computer Science student and a Linux enthusiast who is crazy about web performance. I am really excited to work with our team of amazing mentors, developers and designers at The EOS Design System. Cheers to my journey as I share what I did before the official coding period starts.

What did I do this week?

“Live as if you were to die tomorrow. Learn as if you were to live forever.” — Mahatma Gandhi

I spent much of my time in learning in-depth the technology stack involved for my project. This mainly includes Strapi, Node.js based headless CMS for the back end and React for the front end. I also learnt about MongoDB and API design principles by implementing a ToDo API with user authentication.

My project work for the week included creating the base with router, linter and formatter configuration used at EOS for client side implementation with Create-React-App.

To save time and energy in the future I followed DRY principle (Don’t repeat yourself) and built a custom template which enables us to select a template to create our project from, while still retaining all of the features of Create React App without ejecting. This is maintained here and we published it as a NPM package here (also my first :P). My mentor Cynthia guided me really well on how to automate the package release with semantic-release and GitLab CI/CD.

What is coming up next?

As planned with my mentors I will create some models in the eos-strapi instance. Models in Strapi are a representation of the database structure and are split into two separate files. A JavaScript file that contains the model options (e.g: lifecycle hooks), and a JSON one that represents the data structure stored in the database.

I will further collaborate with Devesh(my awesome GSOC partner :) to implement authentication, authorization and identification of users on the client (React) and server side (Strapi) which internally uses JWT (JSON Web Token).

Did I get stuck anywhere?

I came across one strange problem while developing the template for Create-React-App. My implementation on running did not download the development dependencies for the project. After exploring the create-react-app repository by Facebook I found a recent commit which fixes the problem here. It will be shipped to production soon. This also helped me to learn more about how our famous zero config create-react-app does that magic internally.

 

This marks an outstanding start to my GSOC journey with PSF and EOS which may continue even beyond time can track. Cheers to an awesome never ending journey :)

 

View Blog Post