From 145091dce1a8e5ea639fd71a1e5b1856ece85e27 Mon Sep 17 00:00:00 2001 From: Lakhan Samani Date: Sat, 26 Feb 2022 18:14:43 +0530 Subject: [PATCH] feat: add well-known jwks.json endpoint --- server/constants/env.go | 12 ++++++--- server/crypto/common.go | 29 ++++++++++++++++++++ server/crypto/ecdsa.go | 14 +++++++--- server/crypto/hmac.go | 13 ++++++--- server/crypto/rsa.go | 43 ++++++++++++------------------ server/env/env.go | 45 ++++++++++++++++++++++++++------ server/env/persist_env.go | 4 --- server/go.mod | 1 + server/go.sum | 20 ++++++++++++++ server/handlers/jwks.go | 21 +++++++++++++++ server/handlers/openid_config.go | 9 +------ server/routes/routes.go | 1 + server/token/auth_token.go | 2 +- 13 files changed, 156 insertions(+), 58 deletions(-) create mode 100644 server/crypto/common.go create mode 100644 server/handlers/jwks.go diff --git a/server/constants/env.go b/server/constants/env.go index 213a125..abf604c 100644 --- a/server/constants/env.go +++ b/server/constants/env.go @@ -20,8 +20,6 @@ const ( EnvKeyAuthorizerURL = "AUTHORIZER_URL" // EnvKeyPort key for env variable PORT EnvKeyPort = "PORT" - // EnvKeyClientID key for env variable CLIENT_ID - EnvKeyClientID = "CLIENT_ID" // EnvKeyAdminSecret key for env variable ADMIN_SECRET EnvKeyAdminSecret = "ADMIN_SECRET" @@ -95,8 +93,14 @@ const ( EnvKeyOrganizationName = "ORGANIZATION_NAME" // EnvKeyOrganizationLogo key for env variable ORGANIZATION_LOGO EnvKeyOrganizationLogo = "ORGANIZATION_LOGO" - // EnvKeyIsProd key for env variable IS_PROD - EnvKeyIsProd = "IS_PROD" // EnvKeyCustomAccessTokenScript key for env variable CUSTOM_ACCESS_TOKEN_SCRIPT EnvKeyCustomAccessTokenScript = "CUSTOM_ACCESS_TOKEN_SCRIPT" + + // Not Exposed Keys + // EnvKeyClientID key for env variable CLIENT_ID + EnvKeyClientID = "CLIENT_ID" + // EnvKeyJWK key for env variable JWK + EnvKeyJWK = "JWK" + // EnvKeyIsProd key for env variable IS_PROD + EnvKeyIsProd = "IS_PROD" ) diff --git a/server/crypto/common.go b/server/crypto/common.go new file mode 100644 index 0000000..22b354e --- /dev/null +++ b/server/crypto/common.go @@ -0,0 +1,29 @@ +package crypto + +import ( + "crypto/x509" + + "gopkg.in/square/go-jose.v2" +) + +// GetPubJWK returns JWK for given keys +func GetPubJWK(algo, keyID string, publicKey interface{}) (string, error) { + jwk := &jose.JSONWebKeySet{ + Keys: []jose.JSONWebKey{ + { + Algorithm: algo, + Key: publicKey, + Use: "sig", + KeyID: keyID, + Certificates: []*x509.Certificate{}, + CertificateThumbprintSHA1: []uint8{}, + CertificateThumbprintSHA256: []uint8{}, + }, + }, + } + jwkPublicKey, err := jwk.Keys[0].MarshalJSON() + if err != nil { + return "", err + } + return string(jwkPublicKey), nil +} diff --git a/server/crypto/ecdsa.go b/server/crypto/ecdsa.go index b76813b..3b8e4b6 100644 --- a/server/crypto/ecdsa.go +++ b/server/crypto/ecdsa.go @@ -10,18 +10,24 @@ import ( ) // NewECDSAKey to generate new ECDSA Key if env is not set -func NewECDSAKey() (*ecdsa.PrivateKey, string, string, error) { +// returns key instance, private key string, public key string, jwk string, error +func NewECDSAKey(algo, keyID string) (*ecdsa.PrivateKey, string, string, string, error) { key, err := ecdsa.GenerateKey(elliptic.P384(), rand.Reader) if err != nil { - return nil, "", "", err + return nil, "", "", "", err } privateKey, publicKey, err := AsECDSAStr(key, &key.PublicKey) if err != nil { - return nil, "", "", err + return nil, "", "", "", err } - return key, privateKey, publicKey, err + jwkPublicKey, err := GetPubJWK(algo, keyID, &key.PublicKey) + if err != nil { + return nil, "", "", "", err + } + + return key, privateKey, publicKey, string(jwkPublicKey), err } // IsECDSA checks if given string is valid ECDSA algo diff --git a/server/crypto/hmac.go b/server/crypto/hmac.go index cb349b5..a70916b 100644 --- a/server/crypto/hmac.go +++ b/server/crypto/hmac.go @@ -1,11 +1,18 @@ package crypto -import "github.com/google/uuid" +import ( + "github.com/google/uuid" +) // NewHMAC key returns new key that can be used to ecnrypt data using HMAC algo -func NewHMACKey() string { +// returns key, string, error +func NewHMACKey(algo, keyID string) (string, string, error) { key := uuid.New().String() - return key + jwkPublicKey, err := GetPubJWK(algo, keyID, []byte(key)) + if err != nil { + return "", "", err + } + return key, string(jwkPublicKey), nil } // IsHMACValid checks if given string is valid HMCA algo diff --git a/server/crypto/rsa.go b/server/crypto/rsa.go index 34edad5..35bebd3 100644 --- a/server/crypto/rsa.go +++ b/server/crypto/rsa.go @@ -9,18 +9,24 @@ import ( ) // NewRSAKey to generate new RSA Key if env is not set -func NewRSAKey() (*rsa.PrivateKey, string, string, error) { +// returns key instance, private key string, public key string, jwk string, error +func NewRSAKey(algo, keyID string) (*rsa.PrivateKey, string, string, string, error) { key, err := rsa.GenerateKey(rand.Reader, 2048) if err != nil { - return nil, "", "", err + return nil, "", "", "", err } privateKey, publicKey, err := AsRSAStr(key, &key.PublicKey) if err != nil { - return nil, "", "", err + return nil, "", "", "", err } - return key, privateKey, publicKey, err + jwkPublicKey, err := GetPubJWK(algo, keyID, &key.PublicKey) + if err != nil { + return nil, "", "", "", err + } + + return key, privateKey, publicKey, string(jwkPublicKey), err } // IsRSA checks if given string is valid RSA algo @@ -46,11 +52,8 @@ func ExportRsaPrivateKeyAsPemStr(privkey *rsa.PrivateKey) string { } // ExportRsaPublicKeyAsPemStr to get RSA public key as pem string -func ExportRsaPublicKeyAsPemStr(pubkey *rsa.PublicKey) (string, error) { - pubkeyBytes, err := x509.MarshalPKIXPublicKey(pubkey) - if err != nil { - return "", err - } +func ExportRsaPublicKeyAsPemStr(pubkey *rsa.PublicKey) string { + pubkeyBytes := x509.MarshalPKCS1PublicKey(pubkey) pubkeyPem := pem.EncodeToMemory( &pem.Block{ Type: "RSA PUBLIC KEY", @@ -58,7 +61,7 @@ func ExportRsaPublicKeyAsPemStr(pubkey *rsa.PublicKey) (string, error) { }, ) - return string(pubkeyPem), nil + return string(pubkeyPem) } // ParseRsaPrivateKeyFromPemStr to parse RSA private key from pem string @@ -83,28 +86,19 @@ func ParseRsaPublicKeyFromPemStr(pubPEM string) (*rsa.PublicKey, error) { return nil, errors.New("failed to parse PEM block containing the key") } - pub, err := x509.ParsePKIXPublicKey(block.Bytes) + pub, err := x509.ParsePKCS1PublicKey(block.Bytes) if err != nil { return nil, err } - switch pub := pub.(type) { - case *rsa.PublicKey: - return pub, nil - default: - break // fall through - } - return nil, errors.New("Key type is not RSA") + return pub, nil } // AsRSAStr returns private, public key string or error func AsRSAStr(privateKey *rsa.PrivateKey, publickKey *rsa.PublicKey) (string, string, error) { // Export the keys to pem string privPem := ExportRsaPrivateKeyAsPemStr(privateKey) - pubPem, err := ExportRsaPublicKeyAsPemStr(publickKey) - if err != nil { - return "", "", err - } + pubPem := ExportRsaPublicKeyAsPemStr(publickKey) // Import the keys from pem string privParsed, err := ParseRsaPrivateKeyFromPemStr(privPem) @@ -118,10 +112,7 @@ func AsRSAStr(privateKey *rsa.PrivateKey, publickKey *rsa.PublicKey) (string, st // Export the newly imported keys privParsedPem := ExportRsaPrivateKeyAsPemStr(privParsed) - pubParsedPem, err := ExportRsaPublicKeyAsPemStr(pubParsed) - if err != nil { - return "", "", err - } + pubParsedPem := ExportRsaPublicKeyAsPemStr(pubParsed) return privParsedPem, pubParsedPem, nil } diff --git a/server/env/env.go b/server/env/env.go index 576f438..8c56638 100644 --- a/server/env/env.go +++ b/server/env/env.go @@ -11,6 +11,7 @@ import ( "github.com/authorizerdev/authorizer/server/envstore" "github.com/authorizerdev/authorizer/server/utils" "github.com/gin-gonic/gin" + "github.com/google/uuid" "github.com/joho/godotenv" ) @@ -77,6 +78,13 @@ func InitAllEnv() error { envData = envstore.EnvInMemoryStoreObj.GetEnvStoreClone() } + clientID := envData.StringEnv[constants.EnvKeyClientID] + // unique client id for each instance + if clientID == "" { + clientID = uuid.New().String() + envData.StringEnv[constants.EnvKeyClientID] = clientID + } + if envData.StringEnv[constants.EnvKeyEnv] == "" { envData.StringEnv[constants.EnvKeyEnv] = os.Getenv(constants.EnvKeyEnv) if envData.StringEnv[constants.EnvKeyEnv] == "" { @@ -126,8 +134,8 @@ func InitAllEnv() error { envData.StringEnv[constants.EnvKeySenderEmail] = os.Getenv(constants.EnvKeySenderEmail) } - algo := "" - if envData.StringEnv[constants.EnvKeyJwtType] == "" { + algo := envData.StringEnv[constants.EnvKeyJwtType] + if algo == "" { envData.StringEnv[constants.EnvKeyJwtType] = os.Getenv(constants.EnvKeyJwtType) if envData.StringEnv[constants.EnvKeyJwtType] == "" { envData.StringEnv[constants.EnvKeyJwtType] = "RS256" @@ -143,12 +151,21 @@ func InitAllEnv() error { if envData.StringEnv[constants.EnvKeyJwtSecret] == "" && crypto.IsHMACA(algo) { envData.StringEnv[constants.EnvKeyJwtSecret] = os.Getenv(constants.EnvKeyJwtSecret) if envData.StringEnv[constants.EnvKeyJwtSecret] == "" { - envData.StringEnv[constants.EnvKeyJwtSecret] = crypto.NewHMACKey() + envData.StringEnv[constants.EnvKeyJwtSecret], envData.StringEnv[constants.EnvKeyJWK], err = crypto.NewHMACKey(algo, clientID) + if err != nil { + return err + } + } else { + envData.StringEnv[constants.EnvKeyJWK], err = crypto.GetPubJWK(algo, clientID, []byte(envData.StringEnv[constants.EnvKeyJwtSecret])) + if err != nil { + return err + } + } } if crypto.IsRSA(algo) || crypto.IsECDSA(algo) { - privateKey, publicKey := "", "" + privateKey, publicKey, jwk := "", "", "" if envData.StringEnv[constants.EnvKeyJwtPrivateKey] == "" { privateKey = os.Getenv(constants.EnvKeyJwtPrivateKey) @@ -162,12 +179,12 @@ func InitAllEnv() error { // if either of them is not present generate new keys if privateKey == "" || publicKey == "" { if crypto.IsRSA(algo) { - _, privateKey, publicKey, err = crypto.NewRSAKey() + _, privateKey, publicKey, jwk, err = crypto.NewRSAKey(algo, clientID) if err != nil { return err } } else if crypto.IsECDSA(algo) { - _, privateKey, publicKey, err = crypto.NewECDSAKey() + _, privateKey, publicKey, jwk, err = crypto.NewECDSAKey(algo, clientID) if err != nil { return err } @@ -180,7 +197,12 @@ func InitAllEnv() error { return err } - _, err = crypto.ParseRsaPublicKeyFromPemStr(publicKey) + publicKeyInstance, err := crypto.ParseRsaPublicKeyFromPemStr(publicKey) + if err != nil { + return err + } + + jwk, err = crypto.GetPubJWK(algo, clientID, publicKeyInstance) if err != nil { return err } @@ -190,15 +212,22 @@ func InitAllEnv() error { return err } - _, err = crypto.ParseEcdsaPublicKeyFromPemStr(publicKey) + publicKeyInstance, err := crypto.ParseEcdsaPublicKeyFromPemStr(publicKey) + if err != nil { + return err + } + + jwk, err = crypto.GetPubJWK(algo, clientID, publicKeyInstance) if err != nil { return err } } } + envData.StringEnv[constants.EnvKeyJWK] = jwk envData.StringEnv[constants.EnvKeyJwtPrivateKey] = privateKey envData.StringEnv[constants.EnvKeyJwtPublicKey] = publicKey + } if envData.StringEnv[constants.EnvKeyJwtRoleClaim] == "" { diff --git a/server/env/persist_env.go b/server/env/persist_env.go index cd44e95..eae32c7 100644 --- a/server/env/persist_env.go +++ b/server/env/persist_env.go @@ -178,9 +178,5 @@ func PersistEnv() error { } } - // ID of env is used to identify the config and declared as client id - // this client id can be used in `aud` section of JWT token - envstore.EnvInMemoryStoreObj.UpdateEnvVariable(constants.StringStoreIdentifier, constants.EnvKeyClientID, env.ID) - return nil } diff --git a/server/go.mod b/server/go.mod index e470a65..447ef5b 100644 --- a/server/go.mod +++ b/server/go.mod @@ -30,6 +30,7 @@ require ( google.golang.org/protobuf v1.27.1 // indirect gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect gopkg.in/mail.v2 v2.3.1 + gopkg.in/square/go-jose.v2 v2.6.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gorm.io/driver/mysql v1.2.1 gorm.io/driver/postgres v1.2.3 diff --git a/server/go.sum b/server/go.sum index bcf90b7..904c6e6 100644 --- a/server/go.sum +++ b/server/go.sum @@ -69,6 +69,9 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/dchest/uniuri v0.0.0-20160212164326-8902c56451e9/go.mod h1:GgB8SF9nRG+GqaDtLcwJZsQFhcogVCJ79j4EdT0c2V4= +github.com/decred/dcrd/crypto/blake256 v1.0.0/go.mod h1:sQl2p6Y26YV+ZOcSTP6thNdn47hh8kt6rqSlvmrXFAc= +github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.0-20210816181553-5444fa50b93d h1:1iy2qD6JEhHKKhUOA9IWs7mjco7lnw2qx8FsRI2wirE= +github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.0-20210816181553-5444fa50b93d/go.mod h1:tmAIfUFEirG/Y8jhZ9M+h36obRZAk/1fcSpXwAVlfqE= github.com/denisenkom/go-mssqldb v0.11.0 h1:9rHa233rhdOyrz2GcP9NM+gi2psgJZ4GWDpL/7ND8HI= github.com/denisenkom/go-mssqldb v0.11.0/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU= github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78= @@ -106,6 +109,8 @@ github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfC github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/goccy/go-json v0.9.4 h1:L8MLKG2mvVXiQu07qB6hmfqeSYQdOnqPot2GhsIwIaI= +github.com/goccy/go-json v0.9.4/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= github.com/gofrs/uuid v4.0.0+incompatible h1:1SD/1F5pU8p29ybwgQSwpQk+mwdRrXCYuPhW6m+TnJw= github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= @@ -256,6 +261,18 @@ github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= github.com/leodido/go-urn v1.2.1 h1:BqpAaACuzVSgi/VLzGZIobT2z4v53pjosyNd9Yv6n/w= github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY= +github.com/lestrrat-go/backoff/v2 v2.0.8 h1:oNb5E5isby2kiro9AgdHLv5N5tint1AnDVVf2E2un5A= +github.com/lestrrat-go/backoff/v2 v2.0.8/go.mod h1:rHP/q/r9aT27n24JQLa7JhSQZCKBBOiM/uP402WwN8Y= +github.com/lestrrat-go/blackmagic v1.0.0 h1:XzdxDbuQTz0RZZEmdU7cnQxUtFUzgCSPq8RCz4BxIi4= +github.com/lestrrat-go/blackmagic v1.0.0/go.mod h1:TNgH//0vYSs8VXDCfkZLgIrVTTXQELZffUV0tz3MtdQ= +github.com/lestrrat-go/httpcc v1.0.0 h1:FszVC6cKfDvBKcJv646+lkh4GydQg2Z29scgUfkOpYc= +github.com/lestrrat-go/httpcc v1.0.0/go.mod h1:tGS/u00Vh5N6FHNkExqGGNId8e0Big+++0Gf8MBnAvE= +github.com/lestrrat-go/iter v1.0.1 h1:q8faalr2dY6o8bV45uwrxq12bRa1ezKrB6oM9FUgN4A= +github.com/lestrrat-go/iter v1.0.1/go.mod h1:zIdgO1mRKhn8l9vrZJZz9TUMMFbQbLeTsbqPDrJ/OJc= +github.com/lestrrat-go/jwx v1.2.19 h1:qxxLmAXNwZpTTvjc4PH21nT7I4wPK6lVv3lVNcZPnUk= +github.com/lestrrat-go/jwx v1.2.19/go.mod h1:bWTBO7IHHVMtNunM8so9MT8wD+euEY1PzGEyCnuI2qM= +github.com/lestrrat-go/option v1.0.0 h1:WqAWL8kh8VcSoD6xjSH34/1m8yxluXQbDeKNfvFeEO4= +github.com/lestrrat-go/option v1.0.0/go.mod h1:5ZHFbivi4xwXxhxY9XHDe2FHo6/Z7WWmtT7T5nBBp3I= github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= @@ -386,6 +403,7 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/crypto v0.0.0-20201216223049-8b5274cf687f/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= +golang.org/x/crypto v0.0.0-20201217014255-9d1352758620/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 h1:7I4JAnoQBe7ZtJcBaYHi5UtiO8tQHbUSXxL+pnGRANg= @@ -684,6 +702,8 @@ gopkg.in/sourcemap.v1 v1.0.5 h1:inv58fC9f9J3TK2Y2R1NPntXEn3/wjWHkonhIUODNTI= gopkg.in/sourcemap.v1 v1.0.5/go.mod h1:2RlvNNSMglmRrcvhfuzp4hQHwOtjxlbjX7UPY/GXb78= gopkg.in/square/go-jose.v2 v2.5.1 h1:7odma5RETjNHWJnR32wx8t+Io4djHE1PqxCFx3iiZ2w= gopkg.in/square/go-jose.v2 v2.5.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= +gopkg.in/square/go-jose.v2 v2.6.0 h1:NGk74WTnPKBNUhNzQX7PYcTLUjoq7mzKk2OKbvwk2iI= +gopkg.in/square/go-jose.v2 v2.6.0/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/server/handlers/jwks.go b/server/handlers/jwks.go new file mode 100644 index 0000000..526c319 --- /dev/null +++ b/server/handlers/jwks.go @@ -0,0 +1,21 @@ +package handlers + +import ( + "encoding/json" + + "github.com/authorizerdev/authorizer/server/constants" + "github.com/authorizerdev/authorizer/server/envstore" + "github.com/gin-gonic/gin" +) + +func JWKsHandler() gin.HandlerFunc { + var data map[string]string + json.Unmarshal([]byte(envstore.EnvInMemoryStoreObj.GetStringStoreEnvVariable(constants.EnvKeyJWK)), &data) + return func(c *gin.Context) { + c.JSON(200, gin.H{ + "keys": []map[string]string{ + data, + }, + }) + } +} diff --git a/server/handlers/openid_config.go b/server/handlers/openid_config.go index 9c22e39..eac91ca 100644 --- a/server/handlers/openid_config.go +++ b/server/handlers/openid_config.go @@ -1,8 +1,6 @@ package handlers import ( - "strings" - "github.com/gin-gonic/gin" "github.com/authorizerdev/authorizer/server/constants" @@ -13,11 +11,6 @@ import ( // OpenIDConfigurationHandler handler for open-id configurations func OpenIDConfigurationHandler() gin.HandlerFunc { return func(c *gin.Context) { - if strings.Contains(envstore.EnvInMemoryStoreObj.GetStringStoreEnvVariable(constants.EnvKeyJwtType), "HS") { - c.JSON(400, gin.H{"error": "openid not supported for HSA algorithm"}) - return - } - issuer := utils.GetHost(c) jwtType := envstore.EnvInMemoryStoreObj.GetStringStoreEnvVariable(constants.EnvKeyJwtType) @@ -26,7 +19,7 @@ func OpenIDConfigurationHandler() gin.HandlerFunc { "authorization_endpoint": issuer + "/authorize", "token_endpoint": issuer + "/oauth/token", "userinfo_endpoint": issuer + "/userinfo", - "jwks_uri": issuer + "/jwks.json", + "jwks_uri": issuer + "/.well-known/jwks.json", "response_types_supported": []string{"code", "token", "id_token", "code token", "code id_token", "token id_token", "code token id_token"}, "scopes_supported": []string{"openid", "email", "profile", "email_verified", "given_name", "family_name", "nick_name", "picture"}, "response_modes_supported": []string{"query", "fragment", "form_post"}, diff --git a/server/routes/routes.go b/server/routes/routes.go index 23ee36e..0544431 100644 --- a/server/routes/routes.go +++ b/server/routes/routes.go @@ -22,6 +22,7 @@ func InitRouter() *gin.Engine { router.GET("/verify_email", handlers.VerifyEmailHandler()) // OPEN ID routes router.GET("/.well-known/openid-configuration", handlers.OpenIDConfigurationHandler()) + router.GET("/.well-known/jwks.json", handlers.JWKsHandler()) router.LoadHTMLGlob("templates/*") // login page app related routes. diff --git a/server/token/auth_token.go b/server/token/auth_token.go index f5a2e44..5906e2d 100644 --- a/server/token/auth_token.go +++ b/server/token/auth_token.go @@ -98,7 +98,7 @@ func CreateAccessToken(user models.User, roles []string) (string, int64, error) claimKey := envstore.EnvInMemoryStoreObj.GetStringStoreEnvVariable(constants.EnvKeyJwtRoleClaim) customClaims := jwt.MapClaims{ "iss": "", - "aud": "", + "aud": envstore.EnvInMemoryStoreObj.GetStringStoreEnvVariable(constants.EnvKeyClientID), "nonce": "", "sub": user.ID, "exp": expiresAt,