orizentic: Token-based authentication and authorization

[ authentication, bsd3, library, program ] [ Propose Tags ]

A library and CLI application for generating and validating authentication tokens and their accompanying database


[Skip to Readme]

Modules

[Index]

Flags

Manual Flags

NameDescriptionDefault
dev

Turn on development settings

Disabled

Use -f <flag> to enable a flag, or -f -<flag> to disable that flag. More info

Downloads

Maintainer's Corner

Package maintainers

For package maintainers and hackage trustees

Candidates

  • No Candidates
Versions [RSS] 0.1.0.0
Dependencies aeson (>=1.0.2 && <1.1), base (>=4.7 && <5), bytestring (>=0.10 && <0.11), containers (>=0.5.7 && <0.6), jwt (>=0.7 && <0.8), mtl (>=2.2 && <2.3), optparse-applicative (>=0.13 && <0.14), orizentic, random (>=1.1 && <1.2), text (>=1.2 && <1.3), time (>=1.6 && <1.7), uuid (>=1.3 && <1.4) [details]
License BSD-3-Clause
Copyright 2017 Savanni D'Gerinel
Author Savanni D'Gerinel
Maintainer example@example.com
Category Authentication
Home page https://github.com/luminescent-dreams/orizentic#readme
Source repo head: git clone https://github.com/luminescent-dreams/orizentic
Uploaded by savannidgerinel at 2017-07-19T17:04:58Z
Distributions
Executables orizentic
Downloads 952 total (6 in the last 30 days)
Rating (no votes yet) [estimated by Bayesian average]
Your Rating
  • λ
  • λ
  • λ
Status Docs available [build log]
Last success reported on 2017-07-19 [all 1 reports]

Readme for orizentic-0.1.0.0

[back to package description]

Orizentic

Orizentic provides a library that streamlines token-based authentication and a CLI tool for maintaining the database.

Credit

The name is a contraction of Auth(oriz)ation/Auth(entic)ation, and credit goes to Daria Phoebe Brashear.

The original idea has been debated online for many years, but the push to make this useful comes from Aria Stewart.

Tokens

Tokens are simple JWTs. This library simplifies the process by easily generating and checking JWTs that have only an issuer, an optional time-to-live, a resource name, a username, and a list of permissions. A typical resulting JWT would look like this:

{ iss = Savanni
, sub = health
, aud = "Savanni Desktop"
, exp = null
, nbf = null
, iat = 1499650083
, jti = 9d57a8d8-d11e-43b2-a4d6-7b82ad043994
, unregisteredClaims = { perms: [ "read", "write" ] }
}

The issuer and audience (or username) are almost entirely for human readability. In this instance, I issued a token that was intended to be used on my desktop system.

The subject in this case is synonymous with Resource and is a name for the resource for which access is being granted. Permissions are a simple list of freeform strings. Both of these are flexible within your application and your authorization checks will use them to verify that the token can be used for the specified purpose.

Usage

A variety of workflows appear in the test code, however this is a workflow that I found to be typical in production code.

Start with creating the context:

claimsLst <- loadClaims "authDbPath"
ctx <- newOrizenticCtx ("JWT secret" :: Web.JWT.Secret) []

Your application monad will need to implement the HasOrizenticCtx type class, or you will need to call all of the orizentic functions with a reader monad.

data AppContext -- Your application context here

instance HasOrizenticCtx AppContext where
    hasOrizenticCtx = ...

A typical authentication/verification function will look like this:

authenticate :: (HasOrizenticCtx m) => JWT UnverifiedJWT -> m False
authenticate token = do
    res <- validateToken token
    case res of
        Nothing -> False    -- The token is invalid. Perhaps not a token at all,
                            -- perhaps not signed with the key for this application,
                            -- or perhaps forged.
        Just jwt -> checkAuthorizations validatePermissions jwt
    where
    -- Validate permissions receives the resource name and a list of
    -- permissions. In this case, the "resource" is a name I designated to the
    -- entire app, and the only valid permissions are read+write. A more
    -- sophisticated app will want a validator with more resource names and more
    -- nuanced permissions.
    validatePermissions rn (Permissions perms) =
            (rn == ResourceName "health")
        &&  ("read"     `elem` perms)
        &&  ("write"    `elem` perms)

CLI

orizentic is a command-line tool which manages a database stored to disk. The database is a plain text format containing JWT claims. It can be easily loaded with this function:

loadClaims :: FilePath -> IO (Either String [JWTClaimsSet])
loadClaims path =
    catch ((eitherDecode . fromStrict) <$> Data.ByteString.readFile path)
          (\e -> if isDoesNotExistError e
                    then pure $ Right []
                    else throw e)

The utility is provided as a convienence for simple applications with rare database changes. Production environments will likely wish to manage this within a more sophisticated application and may wish to use some other storage backend.