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
Benchmarks can be found here
(WIP) https://github.com/Nerzal/gocloak/wiki/Contribute
For release notes please consult the specific releases here
go get github.com/Nerzal/gocloak/v13 import "github.com/Nerzal/gocloak/v13" 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("[email protected]"),
  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.
- idis generated automatically by Keycloak.
- clientIdis configured by users in- Add clientpage.
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 testOr you can run with docker compose using the run-tests script
./run-tests.shor
./run-tests.sh <TestCase>Or you can run the tests on you own keycloak:
export GOCLOAK_TEST_CONFIG=/path/to/gocloak/config.jsonAll 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-testThe 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.