Categorygithub.com/DanielHons/go-jwt-exchange
repository
1.0.1
Repository: https://github.com/danielhons/go-jwt-exchange.git
Documentation: pkg.go.dev

# Packages

No description provided by the author
No description provided by the author

# README

go jwt exchange

A lightweight webproxy to exchange an authorization token.

CI/CD

Go Docker Push

Use

The desired usecase is to translate an incoming Jason Web Token (JWT) into any outgoing authentication token (which does not have to be a JWT) before passing the request to a backend service. This is handy in combination with tools like PostgREST or postgraphile.

While most of such tools already accept symetric and asymetric keys and a bit of parameterization (like extracting the role from the claims via a jsonPath) this might not be enough for more complex cases. If you need to make another rest call, for instance, then a go-based interceptor is handy.

package main

import (
	jwtexchange "github.com/DanielHons/go-jwt-exchange/jwt_exchange"
	jwt "github.com/golang-jwt/jwt"
	"time"
)



func main() {
	proxy := jwtexchange.NewProxy()
	jwtCreator := jwtexchange.DefaultJwtCreator(func(claims jwt.MapClaims) jwt.Claims {
        // Customize the claims
		claims["user_role"] = "admin"
		return claims
	})
	proxy.Start(jwtCreator)

}

Validation of incoming tokens

In the default configuration, a Jason Web Key Set (JWKS) is loaded from the URL provided in the environment variable JWKS_URL. This JWKS will be used to validate the incoming token.

Please note: If the software you are building provides the key

If one needs another validation logic, the current implemention would require to provide a custom implementation for the TokenReader interface:

type MyCustomTokenReader struct{
 // ...
}

func (r MyCustomTokenReader) validate(token string) (jwt.MapClaims, error){
    var tokenClaims: jwt.MapClaims
    //tokenClaims["sub"] = //...
    return tokenClaims

}

proxy.Config.TokenReader = MyCustomTokenReader{}

Configure the token exchange

The proxy contains a configuration with default values read from environment variables but can be changed programatically as well, like

proxy.Config.OutgoingTokenPrefix="" // Do not use "Bearer " prefix
Config PropertyMeaningExampleEnvironment variableDefault
(Constructor argument)Where to pass requests with the new token to"http://oidc.myserver.com/keys"JWKS_URL
(Constructor argument)Secret used to sign outgoing tokens(Random String, >= 64 chars)JWT_SECRET
TargetUrlWhere to pass requests with the new token to"http://internal-service:1234"TARGET_URL
IncomingTokenHeaderKey of the header to look for the incoming token"X_AUTH_TOKEN"TOKEN_HEADER_IN"Authorization"
OutgoingTokenHeaderKey of the header to set the outgoing token"X_AUTH_TOKEN"TOKEN_HEADER_OUT"Authorization"
OutgoingTokenPrefixA prefix to set before the outgoing token (usually "Bearer ")"Bearer ""Bearer "
ProxyBindAddressWhere to pass requests with the new token to"127.0.0.1:80 "BIND_ADDRESS"0.0.0.0:9002"

Creating custom tokens

If the outgoing token is not a JWT (or is fetched from another api instead assembling it in this exchage) you can start the proxy as follows. The token will be injected in the configured header with the configured prefix.

	proxy.Start(jwtexchange.GenericTokenCreator{CreationFunc: func(claims jwt.MapClaims) (string,error){
		// Create your custom logic to assemble a outgoing token, wheatever it looks like
		return "myresultingToken",nil
	}})

Create JWTs

For a convenient creation of JWTs, start the proxy as follows:

	jwtCreator := jwtexchange.DefaultJwtCreator(func(claims jwt.MapClaims) jwt.Claims {
		claims["user_role"] = "admin"
		return claims
	})
	
	proxy.Start(jwtCreator)

This will set the following standard claims automatically based on the configuration

ClaimMeaningValueEnvironment variableDefault
subThe subjectThe sub claim from the incoming token
iatIssued atCurrent unix timestamp (epoch)
nbfNot before (when the token becomes valid)Current unix timestamp (epoch)
expExpired (when the token becomes invalid)Current unix timestamp (epoch) + TTL from env variableOUTGOING_TOKEN_TTL_SECnow + 3
audThe audience for the created tokenFrom configOUTGOING_AUDIENCE