Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

Note: we can also call this using https with some small modifications.


Client authentication with signed JWT with client secret

This is similar to the option above except we sign with the client secret instead of the private key. 

We also use a different algorithm.

The following code demonstrates this:

Code Block
languagebash
titleSigned JWT with client secret
        secret := "NKTh1bfR9HNwllMhdWrDMKhVJHTvwreC"

        token, err := jwt.NewWithClaims(jwt.SigningMethodHS256, claims).SignedString([]byte(secret))
        if err != nil {
                return "", fmt.Errorf("create: sign token: %w", err)
        }


Client keys tab

The client offer many different ways of configuring the authenticatio keys.

To use the JWKS option we need to create a jwks from our private key.

The following code performs this operation:


Code Block
languagetext
titlePEM to JWKS
package main

import (
        "crypto/rsa"
        "encoding/base64"
        "encoding/json"
        "flag"
        "fmt"
        "golang.org/x/crypto/ssh"
        "io/ioutil"
        "math/big"
)

type Jwks struct {
        Keys []Key `json:"keys"`
}
type Key struct {
        Kid string `json:"kid"`
        Kty string `json:"kty"`
        Use string `json:"use"`
        N   string `json:"n"`
        E   string `json:"e"`
}

var privateKeyFile string

func main() {
        flag.StringVar(&privateKeyFile, "keyfile", "/mnt/c/Users/ktimoney/keycloak-certs/client.key", "Location of private key file")

        prvKey, err := ioutil.ReadFile("/mnt/c/Users/ktimoney/keycloak-certs/client.key")
        if err != nil {
                fmt.Println(err)
        }

        parsed, err := ssh.ParseRawPrivateKey(prvKey)
        if err != nil {
                fmt.Println(err)
        }

        // Convert back to an *rsa.PrivateKey
        privateKey := parsed.(*rsa.PrivateKey)

        publicKey := &privateKey.PublicKey

        jwksKey := Key{
                "something",
                "RSA",
                "sig",
                base64.RawStdEncoding.EncodeToString(publicKey.N.Bytes()),
                base64.RawStdEncoding.EncodeToString(big.NewInt(int64(publicKey.E)).Bytes()),
        }
        jwksKeys := []Key{jwksKey}
        jwks := Jwks{jwksKeys}

        jwksJson, err := json.Marshal(jwks)
        if err != nil {
                fmt.Println(err)
                return
        }
        fmt.Println(string(jwksJson))

}


The output will look like this:

{"keys":[{"kid":"something","kty":"RSA","use":"sig","n":"70XsremwRthZafooWzoDbpj1VnebGnHHLBOTT+A87SWv+WLYtnsDRAew/2XlHA8Q2c1sRU5xeEOtV6tNzk7qk8b4Kp6ZjDSeyUu7IjDEKhJUVaW2rJKj6Cyp9V8Iu82owvMdkyipWp2ZRs7GPtT0CDWSjQnu3nhQ2k0KKybZL9OQ7evpEid7q/pzFPZVU3lEUXiNJZAXTx4AIBZTgM2x74NgORg3WDCpxIPoHB1E2lOkOviAhTC6UmOpUBuLhQIrYTrVfpq0FtlgwCho0hf6uMN2fv60d0EOCEvb1a/8uBLZ2CX5oPvMZ1UfJiLwp/FaYOATmmdRF5CQoLO5AvV7CnOWdisISHIDwq+lMmO9qa8TFbgLZ0OcElgws/O1qJSHXISvWYiruT36XRuxRGg17ctTiI1Fb8qtyz1B7Rmpn0dG52aYfwJ+fZbhkKXwo4Q9SAUsAO8aPEotpCmHXPDeLbXVhgxzevr0WOE2bInU+yQYaF43e4AmzuCRPI2EruM4mAogxj8GkG/SCAVT7lWQeuIFyx3BD5wkOgPrniNVsnMeFq7VvXGpIEcbBz4KfVvlMOiNFh8XCP1YIKPtFqdEhx/NerNLVw0EMWx4iyFlTOr+TSVIi0NDr1GCMwu8SSz5gXHWnWTCZAo7lEFlZevYRV/YphJT310Q78CVyh/uPgE","e":"AQAB"}]}


We can paste this into the "JWKS" test box.

Alternativley we can run a web server to produce this output and use the server url in the "JWKS URI" text box instead.


Note: There is also a nodejs utility available for this, running ssh-keygen -e -m pkcs8 -f /tmp/client.key | pem-jwk | jq '{ "keys":[{kid: "something", kty: .kty , use: "sig", n: .n , e: .e }]}'

will produce the same result as above.

Keycloak Rest API

Documentation for the keycloak Rest API is available here: Keycloak Admin REST API

...