Intro
I had the need recently to provide some admin access to a web application, but adding password management in that application was not worth the trouble. It was much easier to allow users to request a authentication link by email, as this post will show. The web app is dveloped in WebSharper. If you’re a F# developed, you should really check it out! I like that I can develop client and server in one integrated code base, all in F#. Its list of good things is too long to enumerate here, so do yourself a favor and check it out! This post is not a WebSharper tutorial though, if you need one I recomment Alex Peret’s tutorial.
The app I’m covering here is backed by an sqlite database, with admin users listed in the table admins
, which has only two columns: email
and token
.
When admin users want to login, they request the authentication link, which includes their token, to be sent to their email. Clicking on the link will authenticate them, create a session and mark them as logged in, and display the admin page, only available to logged in users.
Admin users are created manually in the database, there’s no registration available, and tokens are random strings. You might want to use more advanced tokens.
Implementation
My authentication path is /a/${token}
and when a token is present, the authentication occurs. When the token is not present, the admin page is displayed if the user accessing it is logged in.
To achieve this I define the corresponding endpoint:
[<EndPoint "/a">] Admin of token:string
If no token is present in the path, the token
value will be the empty string, which is not a valid token ever assigned to a user. That way we can distinguish both cases.
The distinction of both cases it visibile in the code:
Application.MultiPage (fun ctx endpoint ->
match endpoint with
| EndPoint.Home -> HomePage ctx
| EndPoint.About -> AboutPage ctx
| EndPoint.Admin token ->
if token<> "" then
AuthPage ctx token
else
AdminPage ctx
The AuthPage
will simply validate the token. If it is valid, it registers the user as logged in and redirects it to the admin page, otherwise it redirects to the login page.
if validateToken token language then
ctx.UserSession.LoginUser (System.DateTime.Now.ToString()) |> Async.StartImmediate
Content.RedirectTemporary (EndPoint.Admin "")
else
Content.RedirectTemporary EndPoint.Login
Validating the token is simply checking there is a user with the token.
The Admin page itself will check the user accessing it is logged in before displaying its content, and redirect to the login page otherwise:
async {
let! user = ctx.UserSession.GetLoggedInUser()
if user.IsSome then
let body = ...
return! Templating.Main ctx EndPoint.About (t.t("Admin")) [
h1 [] [t.tt "Admin"]
p [] [t.tt "Welcome"]
body
]
else
return! Content.RedirectTemporary EndPoint.Login
}
Note: the t.tt
call is for internationalisation, and will translate the text in the user’s language.
And this is it, we have the authentication done. Sending the authentication link will be shown in a subsequent post, and involves more WebSharper features like client side code, RPC calls, reactive variables. That alone warrants to make it a dedicated post!