Giter Club home page Giter Club logo

virtualzone / jwt-auth-proxy Goto Github PK

View Code? Open in Web Editor NEW
18.0 1.0 7.0 310 KB

A lightweight JWT authentication proxy written in Go designed for use in Docker/Kubernetes environments.

License: Apache License 2.0

Dockerfile 0.98% Smarty 1.62% Shell 1.05% Go 76.79% HTML 0.21% TypeScript 13.58% CSS 0.05% JavaScript 5.72%
jwt jwt-authentication proxy proxy-server auth-proxy auth-provider proxy-auth jwt-middleware jwt-server jwtauth security security-provider authentication docker kubernetes refresh-tokens signup 2fa two-factor-authentication totp

jwt-auth-proxy's Introduction

JWT Auth Proxy

This JWT Auth Proxy is a lightweight authentication proxy written in Go designed for use in Docker/Kubernetes environments.

JWT Auth Proxy

JWT Auth Proxy sits between your frontend and your application's backend, handles authentication, and proxies authenticated requests to your backend. It offers REST APIs and logic for signup (incl. double-opt-in), password reset ("forgot my password") and verified email address change. This way, your application's backend can focus on the actual business logic, while relying on secure authentication having been performed before.

To your application's backend, the JWT Auth Proxy provides an mTLS-secured REST API for modifying user objects and storing custom data per user.

JWT Auth Proxy uses short-lived JWT access tokens (HMAC-signing with SHA-512) and long-lived UUIDv4 refresh tokens for securely retrieving new access tokens before the old one expires. It supports Two-Factor Authentication (2FA) via Time-based One-Time passwords (TOTP).

Features

User-facing

  • Easy-to-use REST API for
    • Signup with double-opt-in
    • Login (with TOTP optionally)
    • Logout
    • Password reset (forgot password)
    • Email address change with double-opt-in
    • JWT access token renewal using long-lived refresh tokens
    • Activate and disable Two-Factor Authentication (2FA, TOTP)
  • Proxy authenticated requests to your application's backend
  • Whitelist backend URLs not requiring authentication (or blacklist)

Application-/Backend-facing

  • mTLS encrypted connecting (mutual TLS)
  • Easy-to-use REST API for
    • Create user
    • Delete user
    • Disable/enable user
    • Check password
    • Set password
    • Set email address
    • Store and retrieve custom per-user data (JSON)

Example

There is a little sample application in the example folder. It consists of the JWT Auth Proxy, a React-based web frontend and a Go-based application backend. It also contains a MongoDB instance and an instance of the Mailhog fake SMTP server.

To start the example:

git clone https://github.com/virtualzone/jwt-auth-proxy.git
cd jwt-auth-proxy/example
docker-compose up -d

Access the frontend at: http://localhost:8080

To access the Mailhog frontend and check for your signup mail: http://localhost:8025

Documentation

https://jwt-auth-proxy.readthedocs.io

jwt-auth-proxy's People

Contributors

virtualzone avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar

jwt-auth-proxy's Issues

The /auth/refresh endpoint return 401 requests with expired accessToken

/auth/refresh endpoint doc is at https://jwt-auth-proxy.readthedocs.io/en/latest/user-facing/#refresh-access-token

Refresh endpoint is for obtaining a valid accessToken with an expired accessToken and a valid refreshToken.

To reproduce

  1. obtain an accessToken and refreshToken pair through login
  2. wait until accessToken is expired
  3. send refresh request

Expected behavior

The server returns a valid accessToken

Actual behavior

The server returns 401

Possible cause

Refresh requests go through a expiration check during VerifyJwtMiddleware function.

Query params in URL bypasses BLACKLIST setting

To reproduce

  1. set PROXY_BLACKLIST to /blacklist
  2. send a GET request to /blacklist without any authorization header
  3. now send another GET request with query params /blacklist?foo=bar without any authorization header

Expected behavior

Both request get 401.

Actual behavior

The second request does not get 401.

Possible cause

I believe the cause is in this function

func VerifyJwtMiddleware(next http.Handler) http.Handler {
var isWhitelistMatch = func(url string, whitelistedURL string) bool {
whitelistedURL = strings.TrimSpace(whitelistedURL)
if strings.HasSuffix(whitelistedURL, "/") {
whitelistedURL = whitelistedURL[:len(whitelistedURL)-1]
}
if whitelistedURL != "" && (url == whitelistedURL || strings.HasPrefix(url, whitelistedURL+"/")) {
return true
}
return false
}
var IsWhitelisted = func(r *http.Request) bool {
url := r.URL.RequestURI()
// Check for whitelisted public API paths
for _, whitelistedURL := range unauthorizedRoutes {
if isWhitelistMatch(url, whitelistedURL) {
return true
}
}
// All other public API paths require a valid auth token
if strings.HasPrefix(url, GetConfig().PublicAPIPath) {
return false
}
// Whitelist Mode: Check is URL is whitelisted, else assume auth token is required
if len(GetConfig().ProxyWhitelist) > 0 {
for _, whitelistedURL := range GetConfig().ProxyWhitelist {
if isWhitelistMatch(url, whitelistedURL) {
return true
}
}
return false
}
// Blacklist Mode: Check is URL is blacklisted, else assume auth token is NOT required
for _, blacklistedURL := range GetConfig().ProxyBlacklist {
if isWhitelistMatch(url, blacklistedURL) {
return false
}
}
return true
}
var HandleWhitelistReq = func(w http.ResponseWriter, r *http.Request) {
claims, authHeader, err := ExtractClaimsFromRequest(r)
if err != nil {
next.ServeHTTP(w, r)
return
}
ctx := context.WithValue(r.Context(), contextKeyUserID, claims.UserID)
ctx = context.WithValue(ctx, contextKeyAuthHeader, authHeader)
next.ServeHTTP(w, r.WithContext(ctx))
}
var HandleNonWhitelistReq = func(w http.ResponseWriter, r *http.Request) {
claims, authHeader, err := ExtractClaimsFromRequest(r)
if err != nil {
log.Println(err)
SendUnauthorized(w)
return
}
ctx := context.WithValue(r.Context(), contextKeyUserID, claims.UserID)
ctx = context.WithValue(ctx, contextKeyAuthHeader, authHeader)
next.ServeHTTP(w, r.WithContext(ctx))
}
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.Method == "OPTIONS" {
HandleWhitelistReq(w, r)
} else if IsWhitelisted(r) {
HandleWhitelistReq(w, r)
} else {
HandleNonWhitelistReq(w, r)
}
})
}

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.