Golang Keycloak API Package
This client is based on: go-keycloak
For Questions either raise an issue, or come to the gopher-slack into the channel #gocloak
If u are using the echo framework have a look at gocloak-echo
(WIP) https://github.com/Nerzal/gocloak/wiki/Contribute
For release notes please consult the specific releases here
go get github.com/Nerzal/gocloak/v14
import "github.com/Nerzal/gocloak/v14"
client := gocloak.NewClient("https://mycool.keycloak.instance")
ctx := context.Background()
token, err := client.LoginAdmin(ctx, "user", "password", "realmName")
if err != nil {
panic("Something wrong with the credentials or url")
}
user := gocloak.User{
FirstName: gocloak.StringP("Bob"),
LastName: gocloak.StringP("Uncle"),
Email: gocloak.StringP("something@really.wrong"),
Enabled: gocloak.BoolP(true),
Username: gocloak.StringP("CoolGuy"),
}
_, err = client.CreateUser(ctx, token.AccessToken, "realm", user)
if err != nil {
panic("Oh no!, failed to create user :(")
}
client := gocloak.NewClient(hostname)
ctx := context.Background()
token, err := client.LoginClient(ctx, clientID, clientSecret, realm)
if err != nil {
panic("Login failed:"+ err.Error())
}
rptResult, err := client.RetrospectToken(ctx, token.AccessToken, clientID, clientSecret, realm)
if err != nil {
panic("Inspection failed:"+ err.Error())
}
if !*rptResult.Active {
panic("Token is not active")
}
permissions := rptResult.Permissions
// Do something with the permissions ;)
Client has 2 identity fields- id and clientId and both are unique in one realm.
id is generated automatically by Keycloak.clientId is configured by users in Add client page.To get the clientId from id, use GetClients method with GetClientsParams{ClientID: &clientName}.
clients, err := c.Client.GetClients(
c.Ctx,
c.JWT.AccessToken,
c.Realm,
gocloak.GetClientsParams{
ClientID: &clientName,
},
)
if err != nil {
panic("List clients failed:"+ err.Error())
}
for _, client := range clients {
return *client.ID, nil
}
GoCloakIface holds all methods a client should fulfil.
client := gocloak.NewClient(serverURL)
restyClient := client.RestyClient()
restyClient.SetDebug(true)
restyClient.SetTLSClientConfig(&tls.Config{ InsecureSkipVerify: true })
For local testing you need to start a docker container. Simply run following commands prior to starting the tests:
docker pull quay.io/keycloak/keycloak
docker run -d \
-e KEYCLOAK_USER=admin \
-e KEYCLOAK_PASSWORD=secret \
-e KEYCLOAK_IMPORT=/tmp/gocloak-realm.json \
-v "`pwd`/testdata/gocloak-realm.json:/tmp/gocloak-realm.json" \
-p 8080:8080 \
--name gocloak-test \
quay.io/keycloak/keycloak:latest -Dkeycloak.profile.feature.upload_scripts=enabled
go test
Or you can run with docker compose using the run-tests script
./run-tests.sh
or
./run-tests.sh <TestCase>
Or you can run the tests on you own keycloak:
export GOCLOAK_TEST_CONFIG=/path/to/gocloak/config.json
All resources created as a result of unit tests will be deleted, except for the test user defined in the configuration file.
To remove running docker container after completion of tests:
docker stop gocloak-test
docker rm gocloak-test
The custom types contain many pointers, so printing them yields mostly pointer values, which aren't much help when debugging your application. For example
someRealmRepresentation := gocloak.RealmRepresentation{
<snip>
}
fmt.Println(someRealmRepresentation)
yields a large set of pointer values
{<nil> <nil> <nil> <nil> <nil> <nil> <nil> <nil> <nil> <nil> <nil> <nil> <nil> <nil> <nil> <nil> <nil> <nil> <nil> <nil> 0xc00000e960 <nil> <nil> <nil> <nil> <nil> <nil> <nil> <nil> 0xc000093cf0 <nil> <nil> <nil> <nil> <nil> <nil> <nil> <nil> <nil> <nil> <nil> <nil> <nil> <nil> <nil> <nil> <nil> <nil> <nil> <nil> <nil> <nil> <nil> <nil> <nil> <nil> <nil> <nil> <nil> <nil> <nil> <nil> <nil> <nil> <nil> <nil> <nil> <nil> <nil> <nil> <nil> <nil> <nil> <nil> <nil> <nil> <nil> <nil> null <nil> <nil> <nil> <nil> <nil> <nil> <nil> <nil> <nil> <nil> <nil> <nil> <nil> <nil>}
For convenience, the String() interface has been added so you can easily see the contents, even for nested custom types. For example,
fmt.Println(someRealmRepresentation.String())
yields
{
"clients": [
{
"name": "someClient",
"protocolMappers": [
{
"config": {
"bar": "foo",
"ping": "pong"
},
"name": "someMapper"
}
]
},
{
"name": "AnotherClient"
}
],
"displayName": "someRealm"
}
Note that empty parameters are not included, because of the use of omitempty in the type definitions.
$ claude mcp add gocloak \
-- python -m otcore.mcp_server <graph>