eveauth

package module
v0.0.0-...-05e8102 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 27, 2021 License: MIT Imports: 17 Imported by: 0

README

EveAuth

Auth middleware and request handler wrapper for GO. It uses boltDB to store user data

Included in this guide:

  1. Usage
  1. Changelog
  2. Feedback and Contribute
  3. Licenses

1. Getting started

Install
$ go get github.com/hieunc229/eveauth
Auth Handle Wrapper and Middleware

Use eveauth.AuthMiddleware or eveauth.AuthHandler to authorize users.

import (
    "github.com/hieunc229/eveauth"
)

// It can be used for any router with standard handler
// ie. func (http.ResponseWriter, r *http.Request)
router := mux.NewRouter()

// auth options
authOptions := eveauth.AuthHandlerOptions{
    // allow only member
    // other values can be eveauth.RoleAdmin, eveauth.RoleAnonymous
    Role: eveauth.RoleMember,

	// Set to true to forbid access from users with different RoleLevel.
	// Or set to false (or nil) to forbid only users with lower RoleLevel
    RoleExact: true
}

// Use as middleware
router.Use("/user_only", eveauth.AuthMiddleware(&authOptions))

// Or wrap around a handler
router.HandlerFunc("/user_only", eveauth.AuthHandler(yourHandler, &authOptions))

When there is an anonymous request to these paths, it return the following:

{
    "ok": false,
    "error": "invalid access"
}
Register handler

Use eveauth.RegisterHandler handler to handle create account. Registed users will have eveauth.RoleMember role

router.HandlerFunc("/auth/register", eveauth.RegisterHandler)

The body json data must be:

{
    "data": {
        "username": "xxxxxx",
        "password": "xxxxxx"
    }
}

Success return:

{
    "ok": true
}

Error return:

{
    "error": "error message",
    "ok": false
}
Login handler

Use eveauth.LoginHandler handler to handle login

router.HandlerFunc("/auth/login", eveauth.LoginHandler)

The body json data must be:

{
    "data": {
        "username": "xxxxxx",
        "password": "xxxxxx"
    }
}

Success return:

{
    "data": {
        "token": "jwt token str" // use as bearer token
    },
    "ok": true
}

Error return:

{
    "error": "error message",
    "ok": false
}
Change password handler

Use eveauth.ChangePasswordhandler to handle change password request. Note that the request must be authorized with Bearer token mention above. If you don't have a bearer token, login to get a bearer token first

router.HandlerFunc("/auth/change-password", eveauth.ChangePasswordhandler)

The body json payload must be:

{
    "data": {
        "password": "oldPassword",
        "new_password": "xxxxxxx",

        //// set to `true` to replace the current token with a new one
        "change_token": false, 

        // set to `true` to remove all existing tokens, then add a new one 
        // (i.e useful for logout all other devices feature)
        "clear_tokens": false, 
    }
}

Success response:

{
    "data" {
        // If `change_token` or `clear_tokens` is true, you will need to use this new token
        // Otherwise, this value will be an empty string ("")
        "new_token": "" 
    },
    "ok": true
}

Error response:

{
    "error": "error message",
    "ok": false
}

Here is a change password example using fetch in JavaScript

fetch("/user_only/items/goodItemId", {
    method: "POST",
    headers: {
        'Authorization': 'Bearer <token>'
        // 'Content-Type': 'application/json'
        // ...
    }
    body: JSON.stringify({
        data: {
            password: "xxxxx",
            new_password: "xxxxxxxx"
        }
    })
})
How to use JWT token

After send a login request and receive a sucess response, you'll be given a token. This token is meant to use as Bearer token.

Whenever you make a request and want it to be authorized, added Authorization: Bearer <token> to the request header

Here is an example with fetch in JavaScript

fetch("/user_only/items/goodItemId", {
    method: "POST",
    headers: {
        'Authorization': 'Bearer <token>'
        // 'Content-Type': 'application/json'
        // ...
    }
    // body: ...
})
How to verify a request contains a JWT token

Use eveauth.VerifyRequest(*http.Request, *eveauth.AuthHandlerOptions) (*JWTPayload, err) to verify your http request.

Verify a http.Request by (1) get bearer token, (2) verify if the token is a valid jwt token, (3) get userData then check if token is still active (4) then check if the user has the proper role if authOption != nil

Here is an example:

func yourHandler(w http.ResponseWriter, r *http.Request) {

    payload, err := eveauth.VerifyRequest(r, &eveauth.AuthHandlerOptions{})

    if err != nil {
        // bearer token is not valid or expired
        return;
    }

    // no err, looking good

    username = payload.Username
}
Setup enviroment variables

There are a few enviroment variables that you should update when using the product:

  • EVEAUTH_JWT_SECRET (default eveauth): a secret string to create jwt token
  • EVEAUTH_PATH (default auth): path to your auth database. You can use absolute or relative path. If you use relative path, the path root is where you run the command)

There are 2 ways to set these enviroment variables:

  1. Using flags in command (only used after you build the application (aka binary file)). For example:
$ ./coolapp -EVEAUTH_JWT_SECRET=randomstringnoonecanguess -EVEAUTH_PATH=/ect/safe-area/coolappAuth.db
  1. Use godotenv (or any dotenv alternative). First, install godotenv (go get https://github.com/joho/godotenv), then create a .env at your root directory with the following content:
# .env
EVEAUTH_JWT_SECRET=randomstringnoonecanguess
EVEAUTH_PATH=/ect/safe-area/coolappAuth.db
  1. Load the .env file. Read the manual from dotenv package you use. For example, for godotenv:
package main

import (
    ...
    "github.com/joho/godotenv"
)

func main() {

    // Load .env file
    err := godotenv.Load()
    if err != nil {
        log.Fatal("Error loading .env file")
    }

}

2. Changelog

  • 25 Jun 2021: added roles
  • 24 Jun 2021: initiate project

3. Feedback and Contribute

Always welcome. Please open a new thread

4. Licenses

  • eveauth MIT
  • BoltDB MIT

Documentation

Index

Constants

This section is empty.

Variables

View Source
var (
	RoleAnonymous = "anonymous"
	RoleMember    = "member"
	RoleAdmin     = "admin"
)
View Source
var (
	JWT_SECRET string
	AUTH_PATH  string
)
View Source
var (
	ErrInvalidToken = errors.New("unauthorized access (invalid token)")
	ErrExpiredToken = errors.New("unauthorized access (expired token)")
)
View Source
var AuthBucketName = []byte("auth")
View Source
var AuthTokenBucketName = []byte("auth_tokens")
View Source
var UserRoleLevels = map[string]int{
	RoleAnonymous: 0,
	RoleMember:    1,
	RoleAdmin:     2,
}

Functions

func AuthHandler

func AuthHandler(nextFunc func(http.ResponseWriter, *http.Request), options *AuthHandlerOptions) func(http.ResponseWriter, *http.Request)

func AuthMiddleware

func AuthMiddleware(options *AuthHandlerOptions) func(http.Handler) http.Handler

func ChangePasswordHandler

func ChangePasswordHandler(w http.ResponseWriter, r *http.Request)

func InitiateAuthHandler

func InitiateAuthHandler(w http.ResponseWriter, r *http.Request)

func LoginHandler

func LoginHandler(w http.ResponseWriter, r *http.Request)

func RegisterHandler

func RegisterHandler(w http.ResponseWriter, r *http.Request)

Types

type AuthHandlerOptions

type AuthHandlerOptions struct {
	Role string `json:"role"`

	// Set to true to forbid access from users with different RoleLevel.
	// Or set to false (or nil) to forbid only users with lower RoleLevel
	RoleExact bool `json:"role_exact"`
}

type JWTPayload

type JWTPayload struct {
	ID        string    `json:"id"`
	Username  string    `json:"username"`
	IssuedAt  time.Time `json:"issued_at"`
	ExpiredAt time.Time `json:"expired_at"`
}

func VerifyRequest

func VerifyRequest(r *http.Request, options *AuthHandlerOptions) (*JWTPayload, *userData, string, error)

Verify a http.Request by (1) get bearer token, (2) verify if the token is a valid jwt token, (3) get userData then check if token is still active (4) then check if the user has the proper role if authOption != nil

func (*JWTPayload) Valid

func (payload *JWTPayload) Valid() error

type UserPayload

type UserPayload struct {
	Username string `json:"username"`
	Password string `json:"password"`
	Email    string `json:"email"`
}

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL