https://github.com/klipitkas/tokenauth
API token authentication for go-fiber
https://github.com/klipitkas/tokenauth
api authentication fiber go-fiber golang hacktoberfest token
Last synced: 7 months ago
JSON representation
API token authentication for go-fiber
- Host: GitHub
- URL: https://github.com/klipitkas/tokenauth
- Owner: klipitkas
- License: unlicense
- Created: 2020-09-20T20:07:46.000Z (about 5 years ago)
- Default Branch: master
- Last Pushed: 2023-06-14T14:53:58.000Z (over 2 years ago)
- Last Synced: 2025-01-21T07:11:20.386Z (9 months ago)
- Topics: api, authentication, fiber, go-fiber, golang, hacktoberfest, token
- Language: Go
- Homepage:
- Size: 22.5 KB
- Stars: 0
- Watchers: 2
- Forks: 0
- Open Issues: 3
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
[](https://goreportcard.com/report/github.com/klipitkas/tokenauth)
[](https://github.com/klipitkas/tokenauth/issues)
[](https://github.com/klipitkas/tokenauth/blob/master/LICENSE)# 🔒 Token Authentication
Token Authentication middleware for [Fiber](https://github.com/gofiber/fiber) that provides a basic token authentication.
## 📝 Table of contents
**Examples**
- [In memory](#in-memory)
- [Databases](#databases)
- [Postgres](#postgres)
- [Redis](#redis)**Token Generation**
- [Default](#default-token-generation)
- [Custom](#custom-token-generation)---
### IN MEMORY
Example for in memory token storage:
```go
package mainimport (
"github.com/gofiber/fiber/v2"
"github.com/klipitkas/tokenauth"
)var Tokens = map[string]tokenauth.Claims{
"token": {"user": "john", "email": "john@example.com", "id": "42"},
}func main() {
app := fiber.New()app.Use(tokenauth.New(tokenauth.Config{
Authorizer: func(s string) tokenauth.Claims {
claims, exist := Tokens[s]
if !exist {
return nil
}
return claims
},
}))app.Get("/", func(c *fiber.Ctx) error {
claims := c.Locals("claims").(tokenauth.Claims)
return c.SendString("Hello, " + claims["user"] + " 👋!")
})_ = app.Listen(":3000")
}
```Try to access the route without a token:
```shell
$ curl http://localhost:3000
Unauthorized
```Try to access the route after providing a token:
```shell
$ curl -H 'Authorization: Bearer token' http://localhost:3000
Hello, john 👋!
```### DATABASES
#### POSTGRES
Use docker to launch a new ephemeral postgres database:
```shell
$ docker run -p 5432:5432 -e POSTGRES_PASSWORD=tokenauth -e POSTGRES_USER=tokenauth -e POSTGRES_DB=tokenauth -d postgres
```Try the following example:
```go
package mainimport (
"database/sql"
"fmt"
"log""github.com/gofiber/fiber/v2"
"github.com/klipitkas/tokenauth"_ "github.com/lib/pq"
)const (
host = "localhost"
port = 5432
user = "tokenauth"
pass = "tokenauth"
dbname = "tokenauth"
)var sqlMigration string = `
DROP TABLE IF EXISTS user_tokens;
DROP TABLE IF EXISTS users;CREATE TABLE users (
id INT,
email TEXT,
PRIMARY KEY(id)
);CREATE TABLE user_tokens (
id INT,
user_id INT,
token TEXT,
PRIMARY KEY(id),
UNIQUE(token),
CONSTRAINT fk_customer FOREIGN KEY(user_id) REFERENCES users(id) ON DELETE CASCADE
);`var sqlSeeder string = `
INSERT INTO users VALUES (1, 'john@example.com');
INSERT INTO users VALUES (2, 'jim@example.com');INSERT INTO user_tokens VALUES (1, 1, 'token');
INSERT INTO user_tokens VALUES (2, 2, 'fgu9KILmznhLtQgmr3');
`func main() {
app := fiber.New()// Connect to the database.
db, err := dbConnect(host, user, pass, dbname, port)
if err != nil {
log.Fatalf("Failed to connect to db: %v", err)
}// Run the migrations.
if _, err = db.Exec(sqlMigration); err != nil {
log.Fatalf("Failed to run the migrations: %v", err)
}// Run the seeders.
if _, err = db.Exec(sqlSeeder); err != nil {
log.Fatalf("Failed to run the migrations: %v", err)
}// Use our custom authorizer to verify tokens from the DB.
app.Use(tokenauth.New(tokenauth.Config{Authorizer: dbTokenAuthorizer}))// Our protected route
app.Get("/", func(c *fiber.Ctx) error {
claims := c.Locals("claims").(tokenauth.Claims)
return c.SendString("Hello, user with ID: " + claims["user_id"] + " 👋!")
})_ = app.Listen(":3000")
defer db.Close()
}func dbConnect(host, user, pass, dbname string, port int) (*sql.DB, error) {
connStr := fmt.Sprintf("host=%s port=%d user=%s "+
"password=%s dbname=%s sslmode=disable",
host, port, user, pass, dbname)// Validate the connection arguments
db, err := sql.Open("postgres", connStr)
if err != nil {
return nil, fmt.Errorf("connect to db: %v", err)
}if err = db.Ping(); err != nil {
return nil, fmt.Errorf("ping the db: %v", err)
}return db, nil
}func dbTokenAuthorizer(token string) tokenauth.Claims {
// Connect to the database.
db, err := dbConnect(host, user, pass, dbname, port)
if err != nil {
fmt.Printf("connect to db: %v", err)
return nil
}
defer db.Close()// Get the user id if the token is valid.
// You can do more things here, such as JOIN statements with the users
// table and get more information for the user.
rows, err := db.Query("SELECT user_id FROM user_tokens WHERE token = $1", token)
if err != nil || rows.Err() != nil {
fmt.Printf("run query for tokens: %v", err)
return nil
}// Set a default empty user ID.
userID := ""
for rows.Next() {
if err := rows.Scan(&userID); err != nil {
fmt.Printf("get token rows: %v", err)
return nil
}
}// Check if we got a valid (non-zero length) user id.
if len(userID) > 0 {
return tokenauth.Claims{"user_id": userID}
}return nil
}
```Try to access the route without a token:
```shell
$ curl http://localhost:3000
Unauthorized
```Try to access the route after providing a token:
```shell
$ curl -H 'Authorization: Bearer token' http://localhost:3000
Hello, user with ID: 1 👋!
``````shell
$ curl -H 'Authorization: Bearer fgu9KILmznhLtQgmr3' http://localhost:3000
Hello, user with ID: 2 👋!
```### REDIS
Use docker to launch a new ephemeral redis instance:
```shell
$ docker run -p 6379:6379 --name redis -d redis
```Try the following example:
```go
package mainimport (
"github.com/gofiber/fiber/v2"
"github.com/klipitkas/tokenauth""context"
"github.com/go-redis/redis/v8"
)func main() {
app := fiber.New()// Use our custom authorizer to verify tokens from Redis.
app.Use(tokenauth.New(tokenauth.Config{Authorizer: redisTokenAuthorizer}))// Our protected route
app.Get("/", func(c *fiber.Ctx) error {
claims := c.Locals("claims").(tokenauth.Claims)
return c.SendString("Hello, user with details: " + claims["user"] + " !👋")
})_ = app.Listen(":3000")
}func redisTokenAuthorizer(token string) tokenauth.Claims {
// Create a new redis client and connect to Redis instance.
redis := redis.NewClient(&redis.Options{
Addr: "localhost:6379",
Password: "",
DB: 0,
})
defer redis.Close()// Test if connection to Redis works.
if _, err := redis.Ping(context.Background()).Result(); err != nil {
return nil
}// Fetch the user details using the token as a key.
user, err := redis.Get(context.Background(), token).Result()
if err != nil {
return nil
}if len(user) > 0 {
return tokenauth.Claims{"user": user}
}return nil
}
```Now you can create a new token using `redis-cli`:
```shell
$ docker exec -it redis redis-cli
127.0.0.1:6379> set token test
OK
```Try to access the route without a token:
```shell
$ curl http://localhost:3000
Unauthorized
```Try to access the route after providing a token:
```shell
$ curl -H 'Authorization: Bearer token' http://localhost:3000
Hello, user with details: test 👋!
```### Default Token Generation
To generate a new token with the default config:
```go
package mainimport (
"fmt"
"log""github.com/klipitkas/tokenauth"
)func main() {
token, err := tokenauth.NewToken(tokenauth.TokenConfig{})
if err != nil {
log.Fatalf("Token generation failed: %v", err)
}
fmt.Printf("Token: %s", token)
}
```You can specify the following parameters as the token configuration:
```go
// TokenConfig is the struct that contains the config
// for token generation.
type TokenConfig struct {
// Alphabet contains the characters that can be used as parts of the token.
Alphabet string
// Length is the length of the token to generate.
Length int
// Generator is the function that can be used to generate tokens.
Generator func(int, string) (string, error)
}
```### Custom Token Generation
If you want to use a custom function to generate a token:
```go
package mainimport (
"fmt"
"log""github.com/klipitkas/tokenauth"
)func main() {
token, err := tokenauth.NewToken(tokenauth.TokenConfig{
Generator: ultraSecureTokenGenerator,
})
if err != nil {
log.Fatalf("Token generation failed: %v", err)
}
fmt.Printf("Token: %s", token)
}func ultraSecureTokenGenerator(length int, alphabet string) (string, error) {
return "token", nil
}
```