npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@fehujs/auth

v0.1.2

Published

User authentication build-in module for Fehujs apps

Downloads

191

Readme

@fehujs/auth

The auth module can handle user authentication with JWT and HTTP cookies.

It uses bcrypt to hash passwords and jsonwebtoken to generate the authentication tokens.

Models & migrations

Go in src/modules/auth.

Now edit the migrations and models in migrations if you need (default user model contains a name, email, id and a password, the default auth token model contains a userId, a token, an expiration date and an id).

Now you can register these migrations in /src/app/migrations/index.ts (cf. Database module).

Then run the migrations: pnpm run migrate add_auth_token=up add_users=up.

You can now create a controller.

User registration

Here's a demonstration of a view that creates a user:

    const body = request.body
    let user: User | null

    // body validation

    try {
        user = await User.create({ name: body.name, email: body.email, password: body.password})
    } catch (err: any) {
        // handle error
    }

    response = await User.login({ request, response }, user)
    return response.redirect("/users/dashboard")

Please note that the creation part is quite standart, let's focus on the User.login({ request, response }, user).

This method sets a cookie containing the authentication token after a user login. This cookie will serve to the auth middleware to see if the user is allowed to access to a page (it will get the token out of it and then try to get the user). Furthermore, the token will be stored in the database.

User login

There's a part of a login view:

    const body = request.body
    let user: User | null
    
    // body validation

    try {
        user = await User.verifyCrendentials(body.email, body.password)
    } catch (err: any) {
        // some errors could happen here
    }

    if (user) {
        response = await User.login({ request, response }, user)
        return response.redirect("/users/dashboard")
    }

    // wrong credentials

As you can see, we're using User.login() here as well.

Now, let's have a look about User.verifyCredentials(). This method will verify if the password provided by the user matches with the password of the user identified by it's email. The method will return the user if they match, null else.

User logout

Some code from a logout view:

    const user = await User.getCurrentUser(request)
    response = await User.logout({ request, response }, user!)  // user exists in all cases thanks to the middleware
    return response.redirect("/users/login")

First of all, we get the current user logged in with the User.getCurrentUser() method (we'll use this method to get the current user if we need them).

Then, we call User.logout(), that will suppress the auth token cookie and the token in the database too.

Middleware & protect routes

Auth middleware

Now let's have a look on the Auth middleware (you can learn how does a middleware in the same time):

export class AuthMiddleware extends Middleware {
    public async handle({ req, request, response}: HttpContext) {
        const user = await User.getCurrentUser(request)

        if (!user) {
            response = request.cookieHandler.deleteCookie(response, CONFIG.modules.auth.TOKEN_COOKIE_NAME)
            response = response.redirect("/users/login?loginRequired")
            return { req, request, response }
        }

        return super.handle({ req, request, response })
    }
}

So, first, it will try to get the current user. Then, if they doesn't exist, it will destroy the auth token cookie and return a redirection to the login page. If the user exists, the system will call the next middleware or the controller.

Note: in the case where user is undefined, the middleware returns the Http Context instead of calling the next middleware. It's because we don't want that the request continues. If you want to reject a request from a middleware, set a middleware exception or define the response (using response.redirect(), response.setResponse() or response.setErrorResponse()).

Register middlewares

You can register a middleware on a route directly:

export const ROUTES: {[key: string]: Route} = {
    // ...
    "GET:/users/dashboard": {
        controller: ["UserController", "dashboard"],
        middlewares: [
            new AuthMiddleware()
        ]
    }
    // ...
}

You just have to add a middleware list containing all middleware.

Note: the middleware will be processed in the same order as they were set:

export const ROUTES: {[key: string]: Route} = {
    // ...
    "GET:/users/dashboard": {
        controller: ["UserController", "dashboard"],
            middlewares: [
                new AuthMiddleware(),
                new SomeMiddleware(),
            ]
        }
    }
    // ...
}

In this case, the AuthMiddleware will be called before the SomeMiddleware.