Thoughts of a software developer

11.08.2018 18:24 | Modified 21.09. 21:22
Golang JWT example with Mithril.js frontend

JWT revisited

This is a second blog post related to JWT. The first one was https://jelinden.fi/blog/simple-golang-jwt-authorize/xFThAkKmR.

Github repository is the same: https://github.com/jelinden/go-jwt (part2 directory).

Server side changes

The major difference on the server side is adding the answering to pages. Or a page, this a SPA app.

router.POST("/api/signup", app.SignupPOST)
router.POST("/api/login", app.LoginPOST)
router.GET("/api/profile", app.AuthorizeMiddleware(http.HandlerFunc(protectedEndpoint)))

router.GET("/login", app.Index)
router.GET("/signup", app.Index)

app.Index is the html from a template.

var tmpl = template.Must(template.ParseFiles("./src/index.html"))

func Index(w http.ResponseWriter, req *http.Request, _ httprouter.Params) {
    tmpl.Execute(w, nil)
}

We are also no longer using static keys and credentials. Our “database” is an in-memory map, no need for a real database in this app. This also means that all signups/credentials are forgotten everytime the app restarts. JWT signing key is taken from environment variable named JWT_KEY. You don’t want to share it publicly.

var secretKey string
var credentials = make(map[string]string)
var tmpl = template.Must(template.ParseFiles("./src/index.html"))

func init() {
    secretKey = os.Getenv("JWT_KEY")
}

Frontend

I added a few pages and the frontend functionality to see how things work. There are basically four pages: signup, login, index page for not logged-in users and a page to which only logged-in users get to see.

I tried out https://mithril.js.org, which seems to be a nice and surprisingly easy framework. Well, easy at least if you’ve used a component base framework before.

Signup basically only takse the credentials and saves them into a map on the server side. It does check if there was a username already saved, but not anything special.

Login page checks if the credentials exists and on succesful login return the token to the client. Client then saves the token to local storage.

service/Login.js:

post: function() {
        return m
            .request({ // login POST request
                method: "POST",
                url: "/api/login",
                data: User.current,
                withCredentials: true
            })
            .then(function(result) {
                if (result && result.token) {
                    localStorage.setItem("token", result.token); // save to local storage
                    location.href = "/"; 
                }
            });
    }

Now, after successful login we are redirected to index page, but we no longer get the “Content for not loggedin users”. Instead, we get

In index.js, in our router, we check if the user is logged-in and choose the routes based on that. That’s how we end up to NotProtected.js after login.

Profile.load().then(function() {
    if (User.current.username) {
        AppRouter();
    } else {
        LoginRouter();
    }
});
function AppRouter() {
    m.route(document.body, "/", {
        "/": {
            render: function() {
                return m(Layout, m(Protected));
            }
        },
        ...
    });
}
function LoginRouter() {
    m.route(document.body, "/", {
        "/": {
            render: function() {
                return m(Layout, m(NotProtected));
            }
        },
        ...
    });
}

I hope this helps some one. Of course, this is not finished and usable as such. In a real world application you would use a real database and add log out functionality. Maybe you would expire tokens after a while and allow renewing them with a different long validity token.