feat: add well-known jwks.json endpoint
This commit is contained in:
parent
ad46210112
commit
145091dce1
|
@ -20,8 +20,6 @@ const (
|
||||||
EnvKeyAuthorizerURL = "AUTHORIZER_URL"
|
EnvKeyAuthorizerURL = "AUTHORIZER_URL"
|
||||||
// EnvKeyPort key for env variable PORT
|
// EnvKeyPort key for env variable PORT
|
||||||
EnvKeyPort = "PORT"
|
EnvKeyPort = "PORT"
|
||||||
// EnvKeyClientID key for env variable CLIENT_ID
|
|
||||||
EnvKeyClientID = "CLIENT_ID"
|
|
||||||
|
|
||||||
// EnvKeyAdminSecret key for env variable ADMIN_SECRET
|
// EnvKeyAdminSecret key for env variable ADMIN_SECRET
|
||||||
EnvKeyAdminSecret = "ADMIN_SECRET"
|
EnvKeyAdminSecret = "ADMIN_SECRET"
|
||||||
|
@ -95,8 +93,14 @@ const (
|
||||||
EnvKeyOrganizationName = "ORGANIZATION_NAME"
|
EnvKeyOrganizationName = "ORGANIZATION_NAME"
|
||||||
// EnvKeyOrganizationLogo key for env variable ORGANIZATION_LOGO
|
// EnvKeyOrganizationLogo key for env variable ORGANIZATION_LOGO
|
||||||
EnvKeyOrganizationLogo = "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 key for env variable CUSTOM_ACCESS_TOKEN_SCRIPT
|
||||||
EnvKeyCustomAccessTokenScript = "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"
|
||||||
)
|
)
|
||||||
|
|
29
server/crypto/common.go
Normal file
29
server/crypto/common.go
Normal file
|
@ -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
|
||||||
|
}
|
|
@ -10,18 +10,24 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
// NewECDSAKey to generate new ECDSA Key if env is not set
|
// 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)
|
key, err := ecdsa.GenerateKey(elliptic.P384(), rand.Reader)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, "", "", err
|
return nil, "", "", "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
privateKey, publicKey, err := AsECDSAStr(key, &key.PublicKey)
|
privateKey, publicKey, err := AsECDSAStr(key, &key.PublicKey)
|
||||||
if err != nil {
|
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
|
// IsECDSA checks if given string is valid ECDSA algo
|
||||||
|
|
|
@ -1,11 +1,18 @@
|
||||||
package crypto
|
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
|
// 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()
|
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
|
// IsHMACValid checks if given string is valid HMCA algo
|
||||||
|
|
|
@ -9,18 +9,24 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
// NewRSAKey to generate new RSA Key if env is not set
|
// 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)
|
key, err := rsa.GenerateKey(rand.Reader, 2048)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, "", "", err
|
return nil, "", "", "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
privateKey, publicKey, err := AsRSAStr(key, &key.PublicKey)
|
privateKey, publicKey, err := AsRSAStr(key, &key.PublicKey)
|
||||||
if err != nil {
|
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
|
// 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
|
// ExportRsaPublicKeyAsPemStr to get RSA public key as pem string
|
||||||
func ExportRsaPublicKeyAsPemStr(pubkey *rsa.PublicKey) (string, error) {
|
func ExportRsaPublicKeyAsPemStr(pubkey *rsa.PublicKey) string {
|
||||||
pubkeyBytes, err := x509.MarshalPKIXPublicKey(pubkey)
|
pubkeyBytes := x509.MarshalPKCS1PublicKey(pubkey)
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
pubkeyPem := pem.EncodeToMemory(
|
pubkeyPem := pem.EncodeToMemory(
|
||||||
&pem.Block{
|
&pem.Block{
|
||||||
Type: "RSA PUBLIC KEY",
|
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
|
// 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")
|
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 {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
switch pub := pub.(type) {
|
|
||||||
case *rsa.PublicKey:
|
|
||||||
return pub, nil
|
return pub, nil
|
||||||
default:
|
|
||||||
break // fall through
|
|
||||||
}
|
|
||||||
return nil, errors.New("Key type is not RSA")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// AsRSAStr returns private, public key string or error
|
// AsRSAStr returns private, public key string or error
|
||||||
func AsRSAStr(privateKey *rsa.PrivateKey, publickKey *rsa.PublicKey) (string, string, error) {
|
func AsRSAStr(privateKey *rsa.PrivateKey, publickKey *rsa.PublicKey) (string, string, error) {
|
||||||
// Export the keys to pem string
|
// Export the keys to pem string
|
||||||
privPem := ExportRsaPrivateKeyAsPemStr(privateKey)
|
privPem := ExportRsaPrivateKeyAsPemStr(privateKey)
|
||||||
pubPem, err := ExportRsaPublicKeyAsPemStr(publickKey)
|
pubPem := ExportRsaPublicKeyAsPemStr(publickKey)
|
||||||
if err != nil {
|
|
||||||
return "", "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Import the keys from pem string
|
// Import the keys from pem string
|
||||||
privParsed, err := ParseRsaPrivateKeyFromPemStr(privPem)
|
privParsed, err := ParseRsaPrivateKeyFromPemStr(privPem)
|
||||||
|
@ -118,10 +112,7 @@ func AsRSAStr(privateKey *rsa.PrivateKey, publickKey *rsa.PublicKey) (string, st
|
||||||
|
|
||||||
// Export the newly imported keys
|
// Export the newly imported keys
|
||||||
privParsedPem := ExportRsaPrivateKeyAsPemStr(privParsed)
|
privParsedPem := ExportRsaPrivateKeyAsPemStr(privParsed)
|
||||||
pubParsedPem, err := ExportRsaPublicKeyAsPemStr(pubParsed)
|
pubParsedPem := ExportRsaPublicKeyAsPemStr(pubParsed)
|
||||||
if err != nil {
|
|
||||||
return "", "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
return privParsedPem, pubParsedPem, nil
|
return privParsedPem, pubParsedPem, nil
|
||||||
}
|
}
|
||||||
|
|
45
server/env/env.go
vendored
45
server/env/env.go
vendored
|
@ -11,6 +11,7 @@ import (
|
||||||
"github.com/authorizerdev/authorizer/server/envstore"
|
"github.com/authorizerdev/authorizer/server/envstore"
|
||||||
"github.com/authorizerdev/authorizer/server/utils"
|
"github.com/authorizerdev/authorizer/server/utils"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/google/uuid"
|
||||||
"github.com/joho/godotenv"
|
"github.com/joho/godotenv"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -77,6 +78,13 @@ func InitAllEnv() error {
|
||||||
envData = envstore.EnvInMemoryStoreObj.GetEnvStoreClone()
|
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] == "" {
|
if envData.StringEnv[constants.EnvKeyEnv] == "" {
|
||||||
envData.StringEnv[constants.EnvKeyEnv] = os.Getenv(constants.EnvKeyEnv)
|
envData.StringEnv[constants.EnvKeyEnv] = os.Getenv(constants.EnvKeyEnv)
|
||||||
if envData.StringEnv[constants.EnvKeyEnv] == "" {
|
if envData.StringEnv[constants.EnvKeyEnv] == "" {
|
||||||
|
@ -126,8 +134,8 @@ func InitAllEnv() error {
|
||||||
envData.StringEnv[constants.EnvKeySenderEmail] = os.Getenv(constants.EnvKeySenderEmail)
|
envData.StringEnv[constants.EnvKeySenderEmail] = os.Getenv(constants.EnvKeySenderEmail)
|
||||||
}
|
}
|
||||||
|
|
||||||
algo := ""
|
algo := envData.StringEnv[constants.EnvKeyJwtType]
|
||||||
if envData.StringEnv[constants.EnvKeyJwtType] == "" {
|
if algo == "" {
|
||||||
envData.StringEnv[constants.EnvKeyJwtType] = os.Getenv(constants.EnvKeyJwtType)
|
envData.StringEnv[constants.EnvKeyJwtType] = os.Getenv(constants.EnvKeyJwtType)
|
||||||
if envData.StringEnv[constants.EnvKeyJwtType] == "" {
|
if envData.StringEnv[constants.EnvKeyJwtType] == "" {
|
||||||
envData.StringEnv[constants.EnvKeyJwtType] = "RS256"
|
envData.StringEnv[constants.EnvKeyJwtType] = "RS256"
|
||||||
|
@ -143,12 +151,21 @@ func InitAllEnv() error {
|
||||||
if envData.StringEnv[constants.EnvKeyJwtSecret] == "" && crypto.IsHMACA(algo) {
|
if envData.StringEnv[constants.EnvKeyJwtSecret] == "" && crypto.IsHMACA(algo) {
|
||||||
envData.StringEnv[constants.EnvKeyJwtSecret] = os.Getenv(constants.EnvKeyJwtSecret)
|
envData.StringEnv[constants.EnvKeyJwtSecret] = os.Getenv(constants.EnvKeyJwtSecret)
|
||||||
if envData.StringEnv[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) {
|
if crypto.IsRSA(algo) || crypto.IsECDSA(algo) {
|
||||||
privateKey, publicKey := "", ""
|
privateKey, publicKey, jwk := "", "", ""
|
||||||
|
|
||||||
if envData.StringEnv[constants.EnvKeyJwtPrivateKey] == "" {
|
if envData.StringEnv[constants.EnvKeyJwtPrivateKey] == "" {
|
||||||
privateKey = os.Getenv(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 either of them is not present generate new keys
|
||||||
if privateKey == "" || publicKey == "" {
|
if privateKey == "" || publicKey == "" {
|
||||||
if crypto.IsRSA(algo) {
|
if crypto.IsRSA(algo) {
|
||||||
_, privateKey, publicKey, err = crypto.NewRSAKey()
|
_, privateKey, publicKey, jwk, err = crypto.NewRSAKey(algo, clientID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
} else if crypto.IsECDSA(algo) {
|
} else if crypto.IsECDSA(algo) {
|
||||||
_, privateKey, publicKey, err = crypto.NewECDSAKey()
|
_, privateKey, publicKey, jwk, err = crypto.NewECDSAKey(algo, clientID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -180,7 +197,12 @@ func InitAllEnv() error {
|
||||||
return err
|
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 {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -190,15 +212,22 @@ func InitAllEnv() error {
|
||||||
return err
|
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 {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
envData.StringEnv[constants.EnvKeyJWK] = jwk
|
||||||
envData.StringEnv[constants.EnvKeyJwtPrivateKey] = privateKey
|
envData.StringEnv[constants.EnvKeyJwtPrivateKey] = privateKey
|
||||||
envData.StringEnv[constants.EnvKeyJwtPublicKey] = publicKey
|
envData.StringEnv[constants.EnvKeyJwtPublicKey] = publicKey
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if envData.StringEnv[constants.EnvKeyJwtRoleClaim] == "" {
|
if envData.StringEnv[constants.EnvKeyJwtRoleClaim] == "" {
|
||||||
|
|
4
server/env/persist_env.go
vendored
4
server/env/persist_env.go
vendored
|
@ -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
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,6 +30,7 @@ require (
|
||||||
google.golang.org/protobuf v1.27.1 // indirect
|
google.golang.org/protobuf v1.27.1 // indirect
|
||||||
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect
|
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect
|
||||||
gopkg.in/mail.v2 v2.3.1
|
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
|
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||||
gorm.io/driver/mysql v1.2.1
|
gorm.io/driver/mysql v1.2.1
|
||||||
gorm.io/driver/postgres v1.2.3
|
gorm.io/driver/postgres v1.2.3
|
||||||
|
|
|
@ -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 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
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/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 h1:9rHa233rhdOyrz2GcP9NM+gi2psgJZ4GWDpL/7ND8HI=
|
||||||
github.com/denisenkom/go-mssqldb v0.11.0/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU=
|
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=
|
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-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 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk=
|
||||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
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 h1:1SD/1F5pU8p29ybwgQSwpQk+mwdRrXCYuPhW6m+TnJw=
|
||||||
github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
|
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=
|
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.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 h1:BqpAaACuzVSgi/VLzGZIobT2z4v53pjosyNd9Yv6n/w=
|
||||||
github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY=
|
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.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.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||||
github.com/lib/pq v1.2.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-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-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-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-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-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 h1:7I4JAnoQBe7ZtJcBaYHi5UtiO8tQHbUSXxL+pnGRANg=
|
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/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 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.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 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
|
||||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
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=
|
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
|
|
21
server/handlers/jwks.go
Normal file
21
server/handlers/jwks.go
Normal file
|
@ -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,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,8 +1,6 @@
|
||||||
package handlers
|
package handlers
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
|
|
||||||
"github.com/authorizerdev/authorizer/server/constants"
|
"github.com/authorizerdev/authorizer/server/constants"
|
||||||
|
@ -13,11 +11,6 @@ import (
|
||||||
// OpenIDConfigurationHandler handler for open-id configurations
|
// OpenIDConfigurationHandler handler for open-id configurations
|
||||||
func OpenIDConfigurationHandler() gin.HandlerFunc {
|
func OpenIDConfigurationHandler() gin.HandlerFunc {
|
||||||
return func(c *gin.Context) {
|
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)
|
issuer := utils.GetHost(c)
|
||||||
jwtType := envstore.EnvInMemoryStoreObj.GetStringStoreEnvVariable(constants.EnvKeyJwtType)
|
jwtType := envstore.EnvInMemoryStoreObj.GetStringStoreEnvVariable(constants.EnvKeyJwtType)
|
||||||
|
|
||||||
|
@ -26,7 +19,7 @@ func OpenIDConfigurationHandler() gin.HandlerFunc {
|
||||||
"authorization_endpoint": issuer + "/authorize",
|
"authorization_endpoint": issuer + "/authorize",
|
||||||
"token_endpoint": issuer + "/oauth/token",
|
"token_endpoint": issuer + "/oauth/token",
|
||||||
"userinfo_endpoint": issuer + "/userinfo",
|
"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"},
|
"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"},
|
"scopes_supported": []string{"openid", "email", "profile", "email_verified", "given_name", "family_name", "nick_name", "picture"},
|
||||||
"response_modes_supported": []string{"query", "fragment", "form_post"},
|
"response_modes_supported": []string{"query", "fragment", "form_post"},
|
||||||
|
|
|
@ -22,6 +22,7 @@ func InitRouter() *gin.Engine {
|
||||||
router.GET("/verify_email", handlers.VerifyEmailHandler())
|
router.GET("/verify_email", handlers.VerifyEmailHandler())
|
||||||
// OPEN ID routes
|
// OPEN ID routes
|
||||||
router.GET("/.well-known/openid-configuration", handlers.OpenIDConfigurationHandler())
|
router.GET("/.well-known/openid-configuration", handlers.OpenIDConfigurationHandler())
|
||||||
|
router.GET("/.well-known/jwks.json", handlers.JWKsHandler())
|
||||||
|
|
||||||
router.LoadHTMLGlob("templates/*")
|
router.LoadHTMLGlob("templates/*")
|
||||||
// login page app related routes.
|
// login page app related routes.
|
||||||
|
|
|
@ -98,7 +98,7 @@ func CreateAccessToken(user models.User, roles []string) (string, int64, error)
|
||||||
claimKey := envstore.EnvInMemoryStoreObj.GetStringStoreEnvVariable(constants.EnvKeyJwtRoleClaim)
|
claimKey := envstore.EnvInMemoryStoreObj.GetStringStoreEnvVariable(constants.EnvKeyJwtRoleClaim)
|
||||||
customClaims := jwt.MapClaims{
|
customClaims := jwt.MapClaims{
|
||||||
"iss": "",
|
"iss": "",
|
||||||
"aud": "",
|
"aud": envstore.EnvInMemoryStoreObj.GetStringStoreEnvVariable(constants.EnvKeyClientID),
|
||||||
"nonce": "",
|
"nonce": "",
|
||||||
"sub": user.ID,
|
"sub": user.ID,
|
||||||
"exp": expiresAt,
|
"exp": expiresAt,
|
||||||
|
|
Loading…
Reference in New Issue
Block a user