Repository: mrparkers/terraform-provider-keycloak
Pull request #104 (2019-04-26 11:26:01)

Added user attributes, client auth resources, service account roles

AndrewChubatiuk: @mrparkers 
Hello again. Prepared a PR with some changes
- Added user attributes
- Added client and client authorization policy datasources
- Added client authorization resources (resource, permission, scope)
- Added service account roles resource
Added examples of how to use it
AndrewChubatiuk: @mrparkers 
Fixed all your PR comments and added tests.

Patch:
diff --git a/example/main.tf b/example/main.tf
index d4f7d29..eb6844c 100644
--- a/example/main.tf
+++ b/example/main.tf
@@ -444,3 +444,80 @@ resource keycloak_hardcoded_attribute_identity_provider_mapper saml {
   attribute_value         = "value"
   user_session            = false
 }
+
+data "keycloak_openid_client" "broker" {
+  realm_id  = "${keycloak_realm.test.id}"
+  client_id = "broker"
+}
+
+data "keycloak_openid_client_authorization_policy" "default" {
+  realm_id           = "${keycloak_realm.test.id}"
+  resource_server_id = "${keycloak_openid_client.test_client_auth.resource_server_id}"
+  name               = "default"
+}
+
+resource "keycloak_openid_client" "test_client_auth" {
+  client_id   = "test-client-auth"
+  name        = "test-client-auth"
+  realm_id    = "${keycloak_realm.test.id}"
+  description = "a test openid client"
+
+  access_type                  = "CONFIDENTIAL"
+  direct_access_grants_enabled = true
+  implicit_flow_enabled        = true
+  service_accounts_enabled     = true
+
+  valid_redirect_uris = [
+    "http://localhost:5555/callback",
+  ]
+
+  authorization {
+    policy_enforcement_mode = "ENFORCING"
+  }
+
+  client_secret = "secret"
+}
+
+resource "keycloak_openid_client_authorization_permission" "resource" {
+  resource_server_id = "${keycloak_openid_client.test_client_auth.resource_server_id}"
+  realm_id           = "${keycloak_realm.test.id}"
+  name               = "test"
+  policies           = ["${data.keycloak_openid_client_authorization_policy.default.id}"]
+  resources          = ["${keycloak_openid_client_authorization_resource.resource.id}"]
+}
+
+resource "keycloak_openid_client_authorization_resource" "resource" {
+  resource_server_id = "${keycloak_openid_client.test_client_auth.resource_server_id}"
+  name               = "test-openid-client1"
+  realm_id           = "${keycloak_realm.test.id}"
+
+  uris = [
+    "/endpoint/*"
+  ]
+
+  attributes = {
+    "asdads" = "asdasd"
+  }
+}
+
+resource "keycloak_openid_client_authorization_scope" "resource" {
+  resource_server_id = "${keycloak_openid_client.test_client_auth.resource_server_id}"
+  name               = "test-openid-client1"
+  realm_id           = "${keycloak_realm.test.id}"
+}
+
+resource "keycloak_user" "resource" {
+  realm_id = "${keycloak_realm.test.id}"
+  username = "test"
+
+  attributes = {
+    "key" = "value"
+  }
+}
+
+resource "keycloak_openid_client_service_account_role" "read_token" {
+  realm_id                = "${keycloak_realm.test.id}"
+  client_id               = "${data.keycloak_openid_client.broker.id}"
+  service_account_user_id = "${keycloak_openid_client.test_client_auth.service_account_user_id}"
+  role                    = "read-token"
+}
diff --git a/keycloak/custom_user_federation.go b/keycloak/custom_user_federation.go
index 20c6f19..9ebf1e4 100644
--- a/keycloak/custom_user_federation.go
+++ b/keycloak/custom_user_federation.go
@@ -85,7 +85,7 @@ func (keycloakClient *KeycloakClient) ValidateCustomUserFederation(custom *Custo
 }
 
 func (keycloakClient *KeycloakClient) NewCustomUserFederation(customUserFederation *CustomUserFederation) error {
-	location, err := keycloakClient.post(fmt.Sprintf("/realms/%s/components", customUserFederation.RealmId), convertFromCustomUserFederationToComponent(customUserFederation))
+	_, location, err := keycloakClient.post(fmt.Sprintf("/realms/%s/components", customUserFederation.RealmId), convertFromCustomUserFederationToComponent(customUserFederation))
 	if err != nil {
 		return err
 	}
@@ -98,7 +98,7 @@ func (keycloakClient *KeycloakClient) NewCustomUserFederation(customUserFederati
 func (keycloakClient *KeycloakClient) GetCustomUserFederation(realmId, id string) (*CustomUserFederation, error) {
 	var component *component
 
-	err := keycloakClient.get(fmt.Sprintf("/realms/%s/components/%s", realmId, id), &component)
+	err := keycloakClient.get(fmt.Sprintf("/realms/%s/components/%s", realmId, id), &component, nil)
 	if err != nil {
 		return nil, err
 	}
@@ -111,5 +111,5 @@ func (keycloakClient *KeycloakClient) UpdateCustomUserFederation(customUserFeder
 }
 
 func (keycloakClient *KeycloakClient) DeleteCustomUserFederation(realmId, id string) error {
-	return keycloakClient.delete(fmt.Sprintf("/realms/%s/components/%s", realmId, id))
+	return keycloakClient.delete(fmt.Sprintf("/realms/%s/components/%s", realmId, id), nil)
 }
diff --git a/keycloak/generic_client.go b/keycloak/generic_client.go
index 5f97220..6c98ac6 100644
--- a/keycloak/generic_client.go
+++ b/keycloak/generic_client.go
@@ -16,7 +16,7 @@ type GenericClient struct {
 func (keycloakClient *KeycloakClient) listGenericClients(realmId string) ([]*GenericClient, error) {
 	var clients []*GenericClient
 
-	err := keycloakClient.get(fmt.Sprintf("/realms/%s/clients", realmId), &clients)
+	err := keycloakClient.get(fmt.Sprintf("/realms/%s/clients", realmId), &clients, nil)
 	if err != nil {
 		return nil, err
 	}
diff --git a/keycloak/group.go b/keycloak/group.go
index 370e028..8418f30 100644
--- a/keycloak/group.go
+++ b/keycloak/group.go
@@ -2,7 +2,6 @@ package keycloak
 
 import (
 	"fmt"
-	"net/url"
 	"strings"
 )
 
@@ -79,7 +78,7 @@ func (keycloakClient *KeycloakClient) NewGroup(group *Group) error {
 		createGroupUrl = fmt.Sprintf("/realms/%s/groups/%s/children", group.RealmId, group.ParentId)
 	}
 
-	location, err := keycloakClient.post(createGroupUrl, group)
+	_, location, err := keycloakClient.post(createGroupUrl, group)
 	if err != nil {
 		return err
 	}
@@ -92,7 +91,7 @@ func (keycloakClient *KeycloakClient) NewGroup(group *Group) error {
 func (keycloakClient *KeycloakClient) GetGroup(realmId, id string) (*Group, error) {
 	var group Group
 
-	err := keycloakClient.get(fmt.Sprintf("/realms/%s/groups/%s", realmId, id), &group)
+	err := keycloakClient.get(fmt.Sprintf("/realms/%s/groups/%s", realmId, id), &group, nil)
 	if err != nil {
 		return nil, err
 	}
@@ -114,13 +113,17 @@ func (keycloakClient *KeycloakClient) UpdateGroup(group *Group) error {
 }
 
 func (keycloakClient *KeycloakClient) DeleteGroup(realmId, id string) error {
-	return keycloakClient.delete(fmt.Sprintf("/realms/%s/groups/%s", realmId, id))
+	return keycloakClient.delete(fmt.Sprintf("/realms/%s/groups/%s", realmId, id), nil)
 }
 
 func (keycloakClient *KeycloakClient) ListGroupsWithName(realmId, name string) ([]*Group, error) {
 	var groups []*Group
 
-	err := keycloakClient.get(fmt.Sprintf("/realms/%s/groups?search=%s", realmId, url.QueryEscape(name)), &groups)
+	params := map[string]string{
+		"search": name,
+	}
+
+	err := keycloakClient.get(fmt.Sprintf("/realms/%s/groups", realmId), &groups, params)
 	if err != nil {
 		return nil, err
 	}
@@ -131,7 +134,7 @@ func (keycloakClient *KeycloakClient) ListGroupsWithName(realmId, name string) (
 func (keycloakClient *KeycloakClient) GetGroupMembers(realmId, groupId string) ([]*User, error) {
 	var users []*User
 
-	err := keycloakClient.get(fmt.Sprintf("/realms/%s/groups/%s/members", realmId, groupId), &users)
+	err := keycloakClient.get(fmt.Sprintf("/realms/%s/groups/%s/members", realmId, groupId), &users, nil)
 	if err != nil {
 		return nil, err
 	}
diff --git a/keycloak/identity_provider.go b/keycloak/identity_provider.go
index f536d55..32de6a5 100644
--- a/keycloak/identity_provider.go
+++ b/keycloak/identity_provider.go
@@ -53,7 +53,7 @@ type IdentityProvider struct {
 
 func (keycloakClient *KeycloakClient) NewIdentityProvider(identityProvider *IdentityProvider) error {
 	log.Printf("[WARN] Realm: %s", identityProvider.Realm)
-	_, err := keycloakClient.post(fmt.Sprintf("/realms/%s/identity-provider/instances", identityProvider.Realm), identityProvider)
+	_, _, err := keycloakClient.post(fmt.Sprintf("/realms/%s/identity-provider/instances", identityProvider.Realm), identityProvider)
 	if err != nil {
 		return err
 	}
@@ -65,7 +65,7 @@ func (keycloakClient *KeycloakClient) GetIdentityProvider(realm, alias string) (
 	var identityProvider IdentityProvider
 	identityProvider.Realm = realm
 
-	err := keycloakClient.get(fmt.Sprintf("/realms/%s/identity-provider/instances/%s", realm, alias), &identityProvider)
+	err := keycloakClient.get(fmt.Sprintf("/realms/%s/identity-provider/instances/%s", realm, alias), &identityProvider, nil)
 	if err != nil {
 		return nil, err
 	}
@@ -78,5 +78,5 @@ func (keycloakClient *KeycloakClient) UpdateIdentityProvider(identityProvider *I
 }
 
 func (keycloakClient *KeycloakClient) DeleteIdentityProvider(realm, alias string) error {
-	return keycloakClient.delete(fmt.Sprintf("/realms/%s/identity-provider/instances/%s", realm, alias))
+	return keycloakClient.delete(fmt.Sprintf("/realms/%s/identity-provider/instances/%s", realm, alias), nil)
 }
diff --git a/keycloak/identity_provider_mapper.go b/keycloak/identity_provider_mapper.go
index a90d5d7..f30927a 100644
--- a/keycloak/identity_provider_mapper.go
+++ b/keycloak/identity_provider_mapper.go
@@ -29,7 +29,7 @@ type IdentityProviderMapper struct {
 
 func (keycloakClient *KeycloakClient) NewIdentityProviderMapper(identityProviderMapper *IdentityProviderMapper) error {
 	log.Printf("[WARN] Realm: %s", identityProviderMapper.Realm)
-	location, err := keycloakClient.post(fmt.Sprintf("/realms/%s/identity-provider/instances/%s/mappers", identityProviderMapper.Realm, identityProviderMapper.IdentityProviderAlias), identityProviderMapper)
+	_, location, err := keycloakClient.post(fmt.Sprintf("/realms/%s/identity-provider/instances/%s/mappers", identityProviderMapper.Realm, identityProviderMapper.IdentityProviderAlias), identityProviderMapper)
 	if err != nil {
 		return err
 	}
@@ -44,7 +44,7 @@ func (keycloakClient *KeycloakClient) GetIdentityProviderMapper(realm, alias, id
 	identityProviderMapper.Realm = realm
 	identityProviderMapper.IdentityProviderAlias = alias
 
-	err := keycloakClient.get(fmt.Sprintf("/realms/%s/identity-provider/instances/%s/mappers/%s", realm, alias, id), &identityProviderMapper)
+	err := keycloakClient.get(fmt.Sprintf("/realms/%s/identity-provider/instances/%s/mappers/%s", realm, alias, id), &identityProviderMapper, nil)
 	if err != nil {
 		return nil, err
 	}
@@ -57,5 +57,5 @@ func (keycloakClient *KeycloakClient) UpdateIdentityProviderMapper(identityProvi
 }
 
 func (keycloakClient *KeycloakClient) DeleteIdentityProviderMapper(realm, alias, id string) error {
-	return keycloakClient.delete(fmt.Sprintf("/realms/%s/identity-provider/instances/%s/mappers/%s", realm, alias, id))
+	return keycloakClient.delete(fmt.Sprintf("/realms/%s/identity-provider/instances/%s/mappers/%s", realm, alias, id), nil)
 }
diff --git a/keycloak/keycloak_client.go b/keycloak/keycloak_client.go
index 91a6dfd..f131a97 100644
--- a/keycloak/keycloak_client.go
+++ b/keycloak/keycloak_client.go
@@ -4,6 +4,7 @@ import (
 	"bytes"
 	"encoding/json"
 	"fmt"
+	"io"
 	"io/ioutil"
 	"log"
 	"net/http"
@@ -166,7 +167,7 @@ func (keycloakClient *KeycloakClient) addRequestHeaders(request *http.Request) {
 	request.Header.Set("Authorization", fmt.Sprintf("%s %s", tokenType, accessToken))
 	request.Header.Set("Accept", "application/json")
 
-	if request.Method == http.MethodPost || request.Method == http.MethodPut {
+	if request.Method == http.MethodPost || request.Method == http.MethodPut || request.Method == http.MethodDelete {
 		request.Header.Set("Content-type", "application/json")
 	}
 }
@@ -247,7 +248,7 @@ func (keycloakClient *KeycloakClient) sendRequest(request *http.Request) ([]byte
 	return body, response.Header.Get("Location"), nil
 }
 
-func (keycloakClient *KeycloakClient) get(path string, resource interface{}) error {
+func (keycloakClient *KeycloakClient) get(path string, resource interface{}, params map[string]string) error {
 	resourceUrl := keycloakClient.baseUrl + apiUrl + path
 
 	request, err := http.NewRequest(http.MethodGet, resourceUrl, nil)
@@ -255,6 +256,14 @@ func (keycloakClient *KeycloakClient) get(path string, resource interface{}) err
 		return err
 	}
 
+	if params != nil {
+		query := url.Values{}
+		for k, v := range params {
+			query.Add(k, v)
+		}
+		request.URL.RawQuery = query.Encode()
+	}
+
 	body, _, err := keycloakClient.sendRequest(request)
 	if err != nil {
 		return err
@@ -263,22 +272,22 @@ func (keycloakClient *KeycloakClient) get(path string, resource interface{}) err
 	return json.Unmarshal(body, resource)
 }
 
-func (keycloakClient *KeycloakClient) post(path string, requestBody interface{}) (string, error) {
+func (keycloakClient *KeycloakClient) post(path string, requestBody interface{}) ([]byte, string, error) {
 	resourceUrl := keycloakClient.baseUrl + apiUrl + path
 
 	payload, err := json.Marshal(requestBody)
 	if err != nil {
-		return "", err
+		return nil, "", err
 	}
 
 	request, err := http.NewRequest(http.MethodPost, resourceUrl, bytes.NewReader(payload))
 	if err != nil {
-		return "", err
+		return nil, "", err
 	}
 
-	_, location, err := keycloakClient.sendRequest(request)
+	body, location, err := keycloakClient.sendRequest(request)
 
-	return location, err
+	return body, location, err
 }
 
 func (keycloakClient *KeycloakClient) put(path string, requestBody interface{}) error {
@@ -299,10 +308,20 @@ func (keycloakClient *KeycloakClient) put(path string, requestBody interface{})
 	return err
 }
 
-func (keycloakClient *KeycloakClient) delete(path string) error {
+func (keycloakClient *KeycloakClient) delete(path string, requestBody interface{}) error {
 	resourceUrl := keycloakClient.baseUrl + apiUrl + path
 
-	request, err := http.NewRequest(http.MethodDelete, resourceUrl, nil)
+	var body io.Reader
+
+	if requestBody != nil {
+		payload, err := json.Marshal(requestBody)
+		if err != nil {
+			return err
+		}
+		body = bytes.NewReader(payload)
+	}
+
+	request, err := http.NewRequest(http.MethodDelete, resourceUrl, body)
 	if err != nil {
 		return err
 	}
diff --git a/keycloak/ldap_full_name_mapper.go b/keycloak/ldap_full_name_mapper.go
index 68616f2..bcf677c 100644
--- a/keycloak/ldap_full_name_mapper.go
+++ b/keycloak/ldap_full_name_mapper.go
@@ -82,7 +82,7 @@ func (keycloakClient *KeycloakClient) ValidateLdapFullNameMapper(mapper *LdapFul
 }
 
 func (keycloakClient *KeycloakClient) NewLdapFullNameMapper(ldapFullNameMapper *LdapFullNameMapper) error {
-	location, err := keycloakClient.post(fmt.Sprintf("/realms/%s/components", ldapFullNameMapper.RealmId), convertFromLdapFullNameMapperToComponent(ldapFullNameMapper))
+	_, location, err := keycloakClient.post(fmt.Sprintf("/realms/%s/components", ldapFullNameMapper.RealmId), convertFromLdapFullNameMapperToComponent(ldapFullNameMapper))
 	if err != nil {
 		return err
 	}
@@ -95,7 +95,7 @@ func (keycloakClient *KeycloakClient) NewLdapFullNameMapper(ldapFullNameMapper *
 func (keycloakClient *KeycloakClient) GetLdapFullNameMapper(realmId, id string) (*LdapFullNameMapper, error) {
 	var component *component
 
-	err := keycloakClient.get(fmt.Sprintf("/realms/%s/components/%s", realmId, id), &component)
+	err := keycloakClient.get(fmt.Sprintf("/realms/%s/components/%s", realmId, id), &component, nil)
 	if err != nil {
 		return nil, err
 	}
@@ -108,5 +108,5 @@ func (keycloakClient *KeycloakClient) UpdateLdapFullNameMapper(ldapFullNameMappe
 }
 
 func (keycloakClient *KeycloakClient) DeleteLdapFullNameMapper(realmId, id string) error {
-	return keycloakClient.delete(fmt.Sprintf("/realms/%s/components/%s", realmId, id))
+	return keycloakClient.delete(fmt.Sprintf("/realms/%s/components/%s", realmId, id), nil)
 }
diff --git a/keycloak/ldap_group_mapper.go b/keycloak/ldap_group_mapper.go
index b08dc23..cc7d460 100644
--- a/keycloak/ldap_group_mapper.go
+++ b/keycloak/ldap_group_mapper.go
@@ -153,7 +153,7 @@ func (keycloakClient *KeycloakClient) ValidateLdapGroupMapper(ldapGroupMapper *L
 }
 
 func (keycloakClient *KeycloakClient) NewLdapGroupMapper(ldapGroupMapper *LdapGroupMapper) error {
-	location, err := keycloakClient.post(fmt.Sprintf("/realms/%s/components", ldapGroupMapper.RealmId), convertFromLdapGroupMapperToComponent(ldapGroupMapper))
+	_, location, err := keycloakClient.post(fmt.Sprintf("/realms/%s/components", ldapGroupMapper.RealmId), convertFromLdapGroupMapperToComponent(ldapGroupMapper))
 	if err != nil {
 		return err
 	}
@@ -166,7 +166,7 @@ func (keycloakClient *KeycloakClient) NewLdapGroupMapper(ldapGroupMapper *LdapGr
 func (keycloakClient *KeycloakClient) GetLdapGroupMapper(realmId, id string) (*LdapGroupMapper, error) {
 	var component *component
 
-	err := keycloakClient.get(fmt.Sprintf("/realms/%s/components/%s", realmId, id), &component)
+	err := keycloakClient.get(fmt.Sprintf("/realms/%s/components/%s", realmId, id), &component, nil)
 	if err != nil {
 		return nil, err
 	}
@@ -179,5 +179,5 @@ func (keycloakClient *KeycloakClient) UpdateLdapGroupMapper(ldapGroupMapper *Lda
 }
 
 func (keycloakClient *KeycloakClient) DeleteLdapGroupMapper(realmId, id string) error {
-	return keycloakClient.delete(fmt.Sprintf("/realms/%s/components/%s", realmId, id))
+	return keycloakClient.delete(fmt.Sprintf("/realms/%s/components/%s", realmId, id), nil)
 }
diff --git a/keycloak/ldap_msad_user_account_control_mapper.go b/keycloak/ldap_msad_user_account_control_mapper.go
index d63f53a..a2890bb 100644
--- a/keycloak/ldap_msad_user_account_control_mapper.go
+++ b/keycloak/ldap_msad_user_account_control_mapper.go
@@ -46,7 +46,7 @@ func convertFromComponentToLdapMsadUserAccountControlMapper(component *component
 }
 
 func (keycloakClient *KeycloakClient) NewLdapMsadUserAccountControlMapper(ldapMsadUserAccountControlMapper *LdapMsadUserAccountControlMapper) error {
-	location, err := keycloakClient.post(fmt.Sprintf("/realms/%s/components", ldapMsadUserAccountControlMapper.RealmId), convertFromLdapMsadUserAccountControlMapperToComponent(ldapMsadUserAccountControlMapper))
+	_, location, err := keycloakClient.post(fmt.Sprintf("/realms/%s/components", ldapMsadUserAccountControlMapper.RealmId), convertFromLdapMsadUserAccountControlMapperToComponent(ldapMsadUserAccountControlMapper))
 	if err != nil {
 		return err
 	}
@@ -59,7 +59,7 @@ func (keycloakClient *KeycloakClient) NewLdapMsadUserAccountControlMapper(ldapMs
 func (keycloakClient *KeycloakClient) GetLdapMsadUserAccountControlMapper(realmId, id string) (*LdapMsadUserAccountControlMapper, error) {
 	var component *component
 
-	err := keycloakClient.get(fmt.Sprintf("/realms/%s/components/%s", realmId, id), &component)
+	err := keycloakClient.get(fmt.Sprintf("/realms/%s/components/%s", realmId, id), &component, nil)
 	if err != nil {
 		return nil, err
 	}
@@ -72,5 +72,5 @@ func (keycloakClient *KeycloakClient) UpdateLdapMsadUserAccountControlMapper(lda
 }
 
 func (keycloakClient *KeycloakClient) DeleteLdapMsadUserAccountControlMapper(realmId, id string) error {
-	return keycloakClient.delete(fmt.Sprintf("/realms/%s/components/%s", realmId, id))
+	return keycloakClient.delete(fmt.Sprintf("/realms/%s/components/%s", realmId, id), nil)
 }
diff --git a/keycloak/ldap_user_attribute_mapper.go b/keycloak/ldap_user_attribute_mapper.go
index 0d9d917..3b164bc 100644
--- a/keycloak/ldap_user_attribute_mapper.go
+++ b/keycloak/ldap_user_attribute_mapper.go
@@ -76,7 +76,7 @@ func convertFromComponentToLdapUserAttributeMapper(component *component, realmId
 }
 
 func (keycloakClient *KeycloakClient) NewLdapUserAttributeMapper(ldapUserAttributeMapper *LdapUserAttributeMapper) error {
-	location, err := keycloakClient.post(fmt.Sprintf("/realms/%s/components", ldapUserAttributeMapper.RealmId), convertFromLdapUserAttributeMapperToComponent(ldapUserAttributeMapper))
+	_, location, err := keycloakClient.post(fmt.Sprintf("/realms/%s/components", ldapUserAttributeMapper.RealmId), convertFromLdapUserAttributeMapperToComponent(ldapUserAttributeMapper))
 	if err != nil {
 		return err
 	}
@@ -89,7 +89,7 @@ func (keycloakClient *KeycloakClient) NewLdapUserAttributeMapper(ldapUserAttribu
 func (keycloakClient *KeycloakClient) GetLdapUserAttributeMapper(realmId, id string) (*LdapUserAttributeMapper, error) {
 	var component *component
 
-	err := keycloakClient.get(fmt.Sprintf("/realms/%s/components/%s", realmId, id), &component)
+	err := keycloakClient.get(fmt.Sprintf("/realms/%s/components/%s", realmId, id), &component, nil)
 	if err != nil {
 		return nil, err
 	}
@@ -102,5 +102,5 @@ func (keycloakClient *KeycloakClient) UpdateLdapUserAttributeMapper(ldapUserAttr
 }
 
 func (keycloakClient *KeycloakClient) DeleteLdapUserAttributeMapper(realmId, id string) error {
-	return keycloakClient.delete(fmt.Sprintf("/realms/%s/components/%s", realmId, id))
+	return keycloakClient.delete(fmt.Sprintf("/realms/%s/components/%s", realmId, id), nil)
 }
diff --git a/keycloak/ldap_user_federation.go b/keycloak/ldap_user_federation.go
index 4528b13..ea1b3d0 100644
--- a/keycloak/ldap_user_federation.go
+++ b/keycloak/ldap_user_federation.go
@@ -303,7 +303,7 @@ func (keycloakClient *KeycloakClient) NewLdapUserFederation(ldapUserFederation *
 		return err
 	}
 
-	location, err := keycloakClient.post(fmt.Sprintf("/realms/%s/components", ldapUserFederation.RealmId), component)
+	_, location, err := keycloakClient.post(fmt.Sprintf("/realms/%s/components", ldapUserFederation.RealmId), component)
 	if err != nil {
 		return err
 	}
@@ -316,7 +316,7 @@ func (keycloakClient *KeycloakClient) NewLdapUserFederation(ldapUserFederation *
 func (keycloakClient *KeycloakClient) GetLdapUserFederation(realmId, id string) (*LdapUserFederation, error) {
 	var component *component
 
-	err := keycloakClient.get(fmt.Sprintf("/realms/%s/components/%s", realmId, id), &component)
+	err := keycloakClient.get(fmt.Sprintf("/realms/%s/components/%s", realmId, id), &component, nil)
 	if err != nil {
 		return nil, err
 	}
@@ -334,5 +334,5 @@ func (keycloakClient *KeycloakClient) UpdateLdapUserFederation(ldapUserFederatio
 }
 
 func (keycloakClient *KeycloakClient) DeleteLdapUserFederation(realmId, id string) error {
-	return keycloakClient.delete(fmt.Sprintf("/realms/%s/components/%s", realmId, id))
+	return keycloakClient.delete(fmt.Sprintf("/realms/%s/components/%s", realmId, id), nil)
 }
diff --git a/keycloak/openid_audience_protocol_mapper.go b/keycloak/openid_audience_protocol_mapper.go
index 93eef65..3e204e5 100644
--- a/keycloak/openid_audience_protocol_mapper.go
+++ b/keycloak/openid_audience_protocol_mapper.go
@@ -63,7 +63,7 @@ func (protocolMapper *protocolMapper) convertToOpenIdAudienceProtocolMapper(real
 func (keycloakClient *KeycloakClient) GetOpenIdAudienceProtocolMapper(realmId, clientId, clientScopeId, mapperId string) (*OpenIdAudienceProtocolMapper, error) {
 	var protocolMapper *protocolMapper
 
-	err := keycloakClient.get(individualProtocolMapperPath(realmId, clientId, clientScopeId, mapperId), &protocolMapper)
+	err := keycloakClient.get(individualProtocolMapperPath(realmId, clientId, clientScopeId, mapperId), &protocolMapper, nil)
 	if err != nil {
 		return nil, err
 	}
@@ -72,13 +72,13 @@ func (keycloakClient *KeycloakClient) GetOpenIdAudienceProtocolMapper(realmId, c
 }
 
 func (keycloakClient *KeycloakClient) DeleteOpenIdAudienceProtocolMapper(realmId, clientId, clientScopeId, mapperId string) error {
-	return keycloakClient.delete(individualProtocolMapperPath(realmId, clientId, clientScopeId, mapperId))
+	return keycloakClient.delete(individualProtocolMapperPath(realmId, clientId, clientScopeId, mapperId), nil)
 }
 
 func (keycloakClient *KeycloakClient) NewOpenIdAudienceProtocolMapper(mapper *OpenIdAudienceProtocolMapper) error {
 	path := protocolMapperPath(mapper.RealmId, mapper.ClientId, mapper.ClientScopeId)
 
-	location, err := keycloakClient.post(path, mapper.convertToGenericProtocolMapper())
+	_, location, err := keycloakClient.post(path, mapper.convertToGenericProtocolMapper())
 	if err != nil {
 		return err
 	}
diff --git a/keycloak/openid_client.go b/keycloak/openid_client.go
index e97985e..9bf9ca2 100644
--- a/keycloak/openid_client.go
+++ b/keycloak/openid_client.go
@@ -4,34 +4,79 @@ import (
 	"fmt"
 )
 
-type openidClientSecret struct {
+type OpenidClientRole struct {
+	Id                 string `json:"id"`
+	Name               string `json:"name"`
+	Description        string `json:"description"`
+	ScopeParamRequired bool   `json:"scopeParamRequired"`
+	ClientRole         bool   `json:"clientRole"`
+	ContainerId        string `json:"ContainerId"`
+}
+
+type OpenidClientSecret struct {
 	Type  string `json:"type"`
 	Value string `json:"value"`
 }
 
-type OpenidClient struct {
-	Id                      string `json:"id,omitempty"`
-	ClientId                string `json:"clientId"`
-	RealmId                 string `json:"-"`
-	Name                    string `json:"name"`
-	Protocol                string `json:"protocol"`                // always openid-connect for this resource
-	ClientAuthenticatorType string `json:"clientAuthenticatorType"` // always client-secret for now, don't have a need for JWT here
-	ClientSecret            string `json:"secret,omitempty"`
+type OpenidClientAuthorizationSettings struct {
+	PolicyEnforcementMode         string `json:"policyEnforcementMode,omitempty"`
+	AllowRemoteResourceManagement bool   `json:"allowRemoteResourceManagement,omitempty"`
+	KeepDefaults                  bool   `json:"-"`
+}
 
-	Enabled     bool   `json:"enabled"`
-	Description string `json:"description"`
+type OpenidClient struct {
+	Id                           string                             `json:"id,omitempty"`
+	ClientId                     string                             `json:"clientId"`
+	RealmId                      string                             `json:"-"`
+	Name                         string                             `json:"name"`
+	Protocol                     string                             `json:"protocol"`                // always openid-connect for this resource
+	ClientAuthenticatorType      string                             `json:"clientAuthenticatorType"` // always client-secret for now, don't have a need for JWT here
+	ClientSecret                 string                             `json:"secret,omitempty"`
+	Enabled                      bool                               `json:"enabled"`
+	Description                  string                             `json:"description"`
+	PublicClient                 bool                               `json:"publicClient"`
+	BearerOnly                   bool                               `json:"bearerOnly"`
+	StandardFlowEnabled          bool                               `json:"standardFlowEnabled"`
+	ImplicitFlowEnabled          bool                               `json:"implicitFlowEnabled"`
+	DirectAccessGrantsEnabled    bool                               `json:"directAccessGrantsEnabled"`
+	ServiceAccountsEnabled       bool                               `json:"serviceAccountsEnabled"`
+	AuthorizationServicesEnabled bool                               `json:"authorizationServicesEnabled"`
+	ValidRedirectUris            []string                           `json:"redirectUris"`
+	WebOrigins                   []string                           `json:"webOrigins"`
+	AuthorizationSettings        *OpenidClientAuthorizationSettings `json:"authorizationSettings,omitempty"`
+}
 
-	// Attributes below indicate client access type. If both are false, access type is confidential. Both cannot be true (although the Keycloak API lets you do this)
-	PublicClient bool `json:"publicClient"`
-	BearerOnly   bool `json:"bearerOnly"`
+func (keycloakClient *KeycloakClient) GetClientRoleByName(realm, clientId, name string) (*OpenidClientRole, error) {
+	var clientRole OpenidClientRole
+	err := keycloakClient.get(fmt.Sprintf("/realms/%s/clients/%s/roles/%s", realm, clientId, name), &clientRole, nil)
+	if err != nil {
+		return nil, err
+	}
+	return &clientRole, nil
+}
 
-	StandardFlowEnabled       bool `json:"standardFlowEnabled"`
-	ImplicitFlowEnabled       bool `json:"implicitFlowEnabled"`
-	DirectAccessGrantsEnabled bool `json:"directAccessGrantsEnabled"`
-	ServiceAccountsEnabled    bool `json:"serviceAccountsEnabled"`
+func (keycloakClient *KeycloakClient) GetClientByName(realm, clientId string) (*OpenidClient, error) {
+	var clients []OpenidClient
+	params := map[string]string{"clientId": clientId}
+	err := keycloakClient.get(fmt.Sprintf("/realms/%s/clients", realm), &clients, params)
+	if err != nil {
+		return nil, err
+	}
+	if len(clients) == 0 {
+		return nil, fmt.Errorf("no clients with name %s found", clientId)
+	}
+	client := clients[0]
+	client.RealmId = realm
+	return &client, nil
+}
 
-	ValidRedirectUris []string `json:"redirectUris"`
-	WebOrigins        []string `json:"webOrigins"`
+func (keycloakClient *KeycloakClient) GetOpenidClientServiceAccountUserId(realmId, clientId string) (*User, error) {
+	var serviceAccountUser User
+	err := keycloakClient.get(fmt.Sprintf("/realms/%s/clients/%s/service-account-user", realmId, clientId), &serviceAccountUser, nil)
+	if err != nil {
+		return &serviceAccountUser, err
+	}
+	return &serviceAccountUser, nil
 }
 
 func (keycloakClient *KeycloakClient) ValidateOpenidClient(client *OpenidClient) error {
@@ -54,26 +99,39 @@ func (keycloakClient *KeycloakClient) NewOpenidClient(client *OpenidClient) erro
 	client.Protocol = "openid-connect"
 	client.ClientAuthenticatorType = "client-secret"
 
-	location, err := keycloakClient.post(fmt.Sprintf("/realms/%s/clients", client.RealmId), client)
+	_, location, err := keycloakClient.post(fmt.Sprintf("/realms/%s/clients", client.RealmId), client)
 	if err != nil {
 		return err
 	}
 
 	client.Id = getIdFromLocationHeader(location)
 
+	if authorizationSettings := client.AuthorizationSettings; authorizationSettings != nil {
+		if !(*authorizationSettings).KeepDefaults {
+			resource, err := keycloakClient.GetOpenidClientAuthorizationResourceByName(client.RealmId, client.Id, "default")
+			if err != nil {
+				return err
+			}
+			err = keycloakClient.DeleteOpenidClientAuthorizationResource(resource.RealmId, resource.ResourceServerId, resource.Id)
+			if err != nil {
+				return err
+			}
+		}
+	}
+
 	return nil
 }
 
 func (keycloakClient *KeycloakClient) GetOpenidClient(realmId, id string) (*OpenidClient, error) {
 	var client OpenidClient
-	var clientSecret openidClientSecret
+	var clientSecret OpenidClientSecret
 
-	err := keycloakClient.get(fmt.Sprintf("/realms/%s/clients/%s", realmId, id), &client)
+	err := keycloakClient.get(fmt.Sprintf("/realms/%s/clients/%s", realmId, id), &client, nil)
 	if err != nil {
 		return nil, err
 	}
 
-	err = keycloakClient.get(fmt.Sprintf("/realms/%s/clients/%s/client-secret", realmId, id), &clientSecret)
+	err = keycloakClient.get(fmt.Sprintf("/realms/%s/clients/%s/client-secret", realmId, id), &clientSecret, nil)
 	if err != nil {
 		return nil, err
 	}
@@ -86,9 +144,13 @@ func (keycloakClient *KeycloakClient) GetOpenidClient(realmId, id string) (*Open
 
 func (keycloakClient *KeycloakClient) GetOpenidClientByClientId(realmId, clientId string) (*OpenidClient, error) {
 	var clients []OpenidClient
-	var clientSecret openidClientSecret
+	var clientSecret OpenidClientSecret
+
+	params := map[string]string{
+		"clientId": clientId,
+	}
 
-	err := keycloakClient.get(fmt.Sprintf("/realms/%s/clients?clientId=%s", realmId, clientId), &clients)
+	err := keycloakClient.get(fmt.Sprintf("/realms/%s/clients", realmId), &clients, params)
 	if err != nil {
 		return nil, err
 	}
@@ -99,7 +161,7 @@ func (keycloakClient *KeycloakClient) GetOpenidClientByClientId(realmId, clientI
 
 	client := clients[0]
 
-	err = keycloakClient.get(fmt.Sprintf("/realms/%s/clients/%s/client-secret", realmId, client.Id), &clientSecret)
+	err = keycloakClient.get(fmt.Sprintf("/realms/%s/clients/%s/client-secret", realmId, client.Id), &clientSecret, nil)
 	if err != nil {
 		return nil, err
 	}
@@ -118,13 +180,13 @@ func (keycloakClient *KeycloakClient) UpdateOpenidClient(client *OpenidClient) e
 }
 
 func (keycloakClient *KeycloakClient) DeleteOpenidClient(realmId, id string) error {
-	return keycloakClient.delete(fmt.Sprintf("/realms/%s/clients/%s", realmId, id))
+	return keycloakClient.delete(fmt.Sprintf("/realms/%s/clients/%s", realmId, id), nil)
 }
 
 func (keycloakClient *KeycloakClient) getOpenidClientScopes(realmId, clientId, t string) ([]*OpenidClientScope, error) {
 	var scopes []*OpenidClientScope
 
-	err := keycloakClient.get(fmt.Sprintf("/realms/%s/clients/%s/%s-client-scopes", realmId, clientId, t), &scopes)
+	err := keycloakClient.get(fmt.Sprintf("/realms/%s/clients/%s/%s-client-scopes", realmId, clientId, t), &scopes, nil)
 	if err != nil {
 		return nil, err
 	}
@@ -207,7 +269,7 @@ func (keycloakClient *KeycloakClient) detachOpenidClientScopes(realmId, clientId
 	}
 
 	for _, openidClientScope := range allOpenidClientScopes {
-		err := keycloakClient.delete(fmt.Sprintf("/realms/%s/clients/%s/%s-client-scopes/%s", realmId, clientId, t, openidClientScope.Id))
+		err := keycloakClient.delete(fmt.Sprintf("/realms/%s/clients/%s/%s-client-scopes/%s", realmId, clientId, t, openidClientScope.Id), nil)
 		if err != nil {
 			return err
 		}
diff --git a/keycloak/openid_client_authorization_permission.go b/keycloak/openid_client_authorization_permission.go
new file mode 100644
index 0000000..f8403b0
--- /dev/null
+++ b/keycloak/openid_client_authorization_permission.go
@@ -0,0 +1,78 @@
+package keycloak
+
+import (
+	"encoding/json"
+	"fmt"
+)
+
+type OpenidClientAuthorizationPermission struct {
+	Id               string   `json:"id,omitempty"`
+	RealmId          string   `json:"-"`
+	ResourceServerId string   `json:"-"`
+	Name             string   `json:"name"`
+	Description      string   `json:"description"`
+	DecisionStrategy string   `json:"decisionStrategy"`
+	Policies         []string `json:"policies"`
+	Resources        []string `json:"resources"`
+	Type             string   `json:"type"`
+}
+
+func (keycloakClient *KeycloakClient) GetOpenidClientAuthorizationPermission(realm, resourceServerId, id string) (*OpenidClientAuthorizationPermission, error) {
+	permission := OpenidClientAuthorizationPermission{
+		RealmId:          realm,
+		ResourceServerId: resourceServerId,
+		Id:               id,
+	}
+
+	policies := []OpenidClientAuthorizationPolicy{}
+	resources := []OpenidClientAuthorizationResource{}
+
+	err := keycloakClient.get(fmt.Sprintf("/realms/%s/clients/%s/authz/resource-server/permission/resource/%s", realm, resourceServerId, id), &permission, nil)
+	if err != nil {
+		return nil, err
+	}
+
+	err = keycloakClient.get(fmt.Sprintf("/realms/%s/clients/%s/authz/resource-server/policy/%s/associatedPolicies", realm, resourceServerId, id), &policies, nil)
+	if err != nil {
+		return nil, err
+	}
+
+	err = keycloakClient.get(fmt.Sprintf("/realms/%s/clients/%s/authz/resource-server/permission/%s/resources", realm, resourceServerId, id), &resources, nil)
+	if err != nil {
+		return nil, err
+	}
+
+	for _, policy := range policies {
+		permission.Policies = append(permission.Policies, policy.Id)
+	}
+
+	for _, resource := range resources {
+		permission.Resources = append(permission.Resources, resource.Id)
+	}
+
+	return &permission, nil
+}
+
+func (keycloakClient *KeycloakClient) NewOpenidClientAuthorizationPermission(permission *OpenidClientAuthorizationPermission) error {
+	body, _, err := keycloakClient.post(fmt.Sprintf("/realms/%s/clients/%s/authz/resource-server/permission", permission.RealmId, permission.ResourceServerId), permission)
+	if err != nil {
+		return err
+	}
+	err = json.Unmarshal(body, &permission)
+	if err != nil {
+		return err
+	}
+	return nil
+}
+
+func (keycloakClient *KeycloakClient) UpdateOpenidClientAuthorizationPermission(permission *OpenidClientAuthorizationPermission) error {
+	err := keycloakClient.put(fmt.Sprintf("/realms/%s/clients/%s/authz/resource-server/permission/resource/%s", permission.RealmId, permission.ResourceServerId, permission.Id), permission)
+	if err != nil {
+		return err
+	}
+	return nil
+}
+
+func (keycloakClient *KeycloakClient) DeleteOpenidClientAuthorizationPermission(realmId, resourceServerId, permissionId string) error {
+	return keycloakClient.delete(fmt.Sprintf("/realms/%s/clients/%s/authz/resource-server/permission/%s", realmId, resourceServerId, permissionId), nil)
+}
diff --git a/keycloak/openid_client_authorization_policy.go b/keycloak/openid_client_authorization_policy.go
new file mode 100644
index 0000000..214fbbe
--- /dev/null
+++ b/keycloak/openid_client_authorization_policy.go
@@ -0,0 +1,33 @@
+package keycloak
+
+import (
+	"fmt"
+)
+
+type OpenidClientAuthorizationPolicy struct {
+	Id               string   `json:"id,omitempty"`
+	RealmId          string   `json:"-"`
+	ResourceServerId string   `json:"-"`
+	Name             string   `json:"name"`
+	Owner            string   `json:"owner"`
+	DecisionStrategy string   `json:"decisionStrategy"`
+	Logic            string   `json:"logic"`
+	Policies         []string `json:"policies"`
+	Resources        []string `json:"resources"`
+	Scopes           []string `json:"scopes"`
+	Type             string   `json:"type"`
+}
+
+func (keycloakClient *KeycloakClient) GetClientAuthorizationPolicyByName(realmId, resourceServerId, name string) (*OpenidClientAuthorizationPolicy, error) {
+	policies := []OpenidClientAuthorizationPolicy{}
+	params := map[string]string{"name": name}
+	err := keycloakClient.get(fmt.Sprintf("/realms/%s/clients/%s/authz/resource-server/policy", realmId, resourceServerId), &policies, params)
+	if err != nil {
+		return nil, err
+	}
+	policy := policies[0]
+	policy.RealmId = realmId
+	policy.ResourceServerId = resourceServerId
+	policy.Name = name
+	return &policy, nil
+}
diff --git a/keycloak/openid_client_authorization_resource.go b/keycloak/openid_client_authorization_resource.go
new file mode 100644
index 0000000..d1b0de6
--- /dev/null
+++ b/keycloak/openid_client_authorization_resource.go
@@ -0,0 +1,70 @@
+package keycloak
+
+import (
+	"encoding/json"
+	"fmt"
+)
+
+type OpenidClientAuthorizationResource struct {
+	ResourceServerId   string                           `json:"-"`
+	RealmId            string                           `json:"-"`
+	Id                 string                           `json:"_id,omitempty"`
+	DisplayName        string                           `json:"displayName"`
+	Name               string                           `json:"name"`
+	Uris               []string                         `json:"uris"`
+	IconUri            string                           `json:"icon_uri"`
+	OwnerManagedAccess bool                             `json:"ownerManagedAccess"`
+	Scopes             []OpenidClientAuthorizationScope `json:"scopes"`
+	Type               string                           `json:"type"`
+	Attributes         map[string][]string              `json:"attributes"`
+}
+
+func (keycloakClient *KeycloakClient) NewOpenidClientAuthorizationResource(resource *OpenidClientAuthorizationResource) error {
+	body, _, err := keycloakClient.post(fmt.Sprintf("/realms/%s/clients/%s/authz/resource-server/resource", resource.RealmId, resource.ResourceServerId), resource)
+	if err != nil {
+		return err
+	}
+	err = json.Unmarshal(body, &resource)
+	if err != nil {
+		return err
+	}
+	return nil
+}
+
+func (keycloakClient *KeycloakClient) GetOpenidClientAuthorizationResource(realm, resourceServerId, resourceId string) (*OpenidClientAuthorizationResource, error) {
+	resource := OpenidClientAuthorizationResource{
+		RealmId:          realm,
+		ResourceServerId: resourceServerId,
+	}
+	err := keycloakClient.get(fmt.Sprintf("/realms/%s/clients/%s/authz/resource-server/resource/%s", realm, resourceServerId, resourceId), &resource, nil)
+	if err != nil {
+		return nil, err
+	}
+	return &resource, nil
+}
+
+func (keycloakClient *KeycloakClient) GetOpenidClientAuthorizationResourceByName(realmId, resourceServerId, name string) (*OpenidClientAuthorizationResource, error) {
+	resources := []OpenidClientAuthorizationResource{}
+	params := map[string]string{"name": name}
+	err := keycloakClient.get(fmt.Sprintf("/realms/%s/clients/%s/authz/resource-server/resource", realmId, resourceServerId), &resources, params)
+	if err != nil {
+		return nil, err
+	}
+	resource := resources[0]
+	resource.RealmId = realmId
+	resource.ResourceServerId = resourceServerId
+	resource.Name = name
+	return &resource, nil
+}
+
+func (keycloakClient *KeycloakClient) UpdateOpenidClientAuthorizationResource(resource *OpenidClientAuthorizationResource) error {
+	err := keycloakClient.put(fmt.Sprintf("/realms/%s/clients/%s/authz/resource-server/resource/%s", resource.RealmId, resource.ResourceServerId, resource.Id), resource)
+	if err != nil {
+		return err
+	}
+	return nil
+}
+
+func (keycloakClient *KeycloakClient) DeleteOpenidClientAuthorizationResource(realmId, clientId, resourceId string) error {
+	return keycloakClient.delete(fmt.Sprintf("/realms/%s/clients/%s/authz/resource-server/resource/%s", realmId, clientId, resourceId), nil)
+}
diff --git a/keycloak/openid_client_authorization_scope.go b/keycloak/openid_client_authorization_scope.go
new file mode 100644
index 0000000..2490f70
--- /dev/null
+++ b/keycloak/openid_client_authorization_scope.go
@@ -0,0 +1,51 @@
+package keycloak
+
+import (
+	"encoding/json"
+	"fmt"
+)
+
+type OpenidClientAuthorizationScope struct {
+	Id               string `json:"id,omitempty"`
+	RealmId          string `json:"-"`
+	ResourceServerId string `json:"-"`
+	Name             string `json:"name"`
+	DisplayName      string `json:"displayName"`
+	IconUri          string `json:"iconUri"`
+}
+
+func (keycloakClient *KeycloakClient) NewOpenidClientAuthorizationScope(scope *OpenidClientAuthorizationScope) error {
+	body, _, err := keycloakClient.post(fmt.Sprintf("/realms/%s/clients/%s/authz/resource-server/scope", scope.RealmId, scope.ResourceServerId), scope)
+	if err != nil {
+		return err
+	}
+	err = json.Unmarshal(body, &scope)
+	if err != nil {
+		return err
+	}
+	return nil
+}
+
+func (keycloakClient *KeycloakClient) GetOpenidClientAuthorizationScope(realm, resourceServerId, scopeId string) (*OpenidClientAuthorizationScope, error) {
+	scope := OpenidClientAuthorizationScope{
+		RealmId:          realm,
+		ResourceServerId: resourceServerId,
+	}
+	err := keycloakClient.get(fmt.Sprintf("/realms/%s/clients/%s/authz/resource-server/scope/%s", realm, resourceServerId, scopeId), &scope, nil)
+	if err != nil {
+		return nil, err
+	}
+	return &scope, nil
+}
+
+func (keycloakClient *KeycloakClient) UpdateOpenidClientAuthorizationScope(scope *OpenidClientAuthorizationScope) error {
+	err := keycloakClient.put(fmt.Sprintf("/realms/%s/clients/%s/authz/resource-server/scope/%s", scope.RealmId, scope.ResourceServerId, scope.Id), scope)
+	if err != nil {
+		return err
+	}
+	return nil
+}
+
+func (keycloakClient *KeycloakClient) DeleteOpenidClientAuthorizationScope(realmId, resourceServerId, scopeId string) error {
+	return keycloakClient.delete(fmt.Sprintf("/realms/%s/clients/%s/authz/resource-server/scope/%s", realmId, resourceServerId, scopeId), nil)
+}
diff --git a/keycloak/openid_client_scope.go b/keycloak/openid_client_scope.go
index 13d9b46..c21aba4 100644
--- a/keycloak/openid_client_scope.go
+++ b/keycloak/openid_client_scope.go
@@ -21,7 +21,7 @@ type OpenidClientScopeFilterFunc func(*OpenidClientScope) bool
 func (keycloakClient *KeycloakClient) NewOpenidClientScope(clientScope *OpenidClientScope) error {
 	clientScope.Protocol = "openid-connect"
 
-	location, err := keycloakClient.post(fmt.Sprintf("/realms/%s/client-scopes", clientScope.RealmId), clientScope)
+	_, location, err := keycloakClient.post(fmt.Sprintf("/realms/%s/client-scopes", clientScope.RealmId), clientScope)
 	if err != nil {
 		return err
 	}
@@ -34,7 +34,7 @@ func (keycloakClient *KeycloakClient) NewOpenidClientScope(clientScope *OpenidCl
 func (keycloakClient *KeycloakClient) GetOpenidClientScope(realmId, id string) (*OpenidClientScope, error) {
 	var clientScope OpenidClientScope
 
-	err := keycloakClient.get(fmt.Sprintf("/realms/%s/client-scopes/%s", realmId, id), &clientScope)
+	err := keycloakClient.get(fmt.Sprintf("/realms/%s/client-scopes/%s", realmId, id), &clientScope, nil)
 	if err != nil {
 		return nil, err
 	}
@@ -51,14 +51,14 @@ func (keycloakClient *KeycloakClient) UpdateOpenidClientScope(clientScope *Openi
 }
 
 func (keycloakClient *KeycloakClient) DeleteOpenidClientScope(realmId, id string) error {
-	return keycloakClient.delete(fmt.Sprintf("/realms/%s/client-scopes/%s", realmId, id))
+	return keycloakClient.delete(fmt.Sprintf("/realms/%s/client-scopes/%s", realmId, id), nil)
 }
 
 func (keycloakClient *KeycloakClient) listOpenidClientScopesWithFilter(realmId string, filter OpenidClientScopeFilterFunc) ([]*OpenidClientScope, error) {
 	var clientScopes []OpenidClientScope
 	var openidClientScopes []*OpenidClientScope
 
-	err := keycloakClient.get(fmt.Sprintf("/realms/%s/client-scopes", realmId), &clientScopes)
+	err := keycloakClient.get(fmt.Sprintf("/realms/%s/client-scopes", realmId), &clientScopes, nil)
 	if err != nil {
 		return nil, err
 	}
diff --git a/keycloak/openid_client_service_account_role.go b/keycloak/openid_client_service_account_role.go
new file mode 100644
index 0000000..d8e6aa8
--- /dev/null
+++ b/keycloak/openid_client_service_account_role.go
@@ -0,0 +1,64 @@
+package keycloak
+
+import (
+	"fmt"
+)
+
+type OpenidClientServiceAccountRole struct {
+	Id                   string `json:"id"`
+	RealmId              string `json:"-"`
+	ServiceAccountUserId string `json:"-"`
+	Name                 string `json:"name,omitempty"`
+	ClientRole           bool   `json:"clientRole"`
+	Composite            bool   `json:"composite"`
+	ContainerId          string `json:"containerId"`
+	Description          string `json:"description"`
+}
+
+func (keycloakClient *KeycloakClient) NewOpenidClientServiceAccountRole(serviceAccountRole *OpenidClientServiceAccountRole) error {
+	role, err := keycloakClient.GetClientRoleByName(serviceAccountRole.RealmId, serviceAccountRole.ContainerId, serviceAccountRole.Name)
+	if err != nil {
+		return err
+	}
+	serviceAccountRole.Id = role.Id
+	serviceAccountRoles := []OpenidClientServiceAccountRole{*serviceAccountRole}
+	_, _, err = keycloakClient.post(fmt.Sprintf("/realms/%s/users/%s/role-mappings/clients/%s", serviceAccountRole.RealmId, serviceAccountRole.ServiceAccountUserId, serviceAccountRole.ContainerId), serviceAccountRoles)
+	if err != nil {
+		return err
+	}
+	return nil
+}
+
+func (keycloakClient *KeycloakClient) DeleteOpenidClientServiceAccountRole(realm, serviceAccountUserId, clientId, roleId string) error {
+	serviceAccountRole, err := keycloakClient.GetOpenidClientServiceAccountRole(realm, serviceAccountUserId, clientId, roleId)
+	if err != nil {
+		return err
+	}
+	serviceAccountRoles := []OpenidClientServiceAccountRole{*serviceAccountRole}
+	err = keycloakClient.delete(fmt.Sprintf("/realms/%s/users/%s/role-mappings/clients/%s", realm, serviceAccountUserId, clientId), &serviceAccountRoles)
+	if err != nil {
+		return err
+	}
+	return nil
+}
+
+func (keycloakClient *KeycloakClient) GetOpenidClientServiceAccountRole(realm, serviceAccountUserId, clientId, roleId string) (*OpenidClientServiceAccountRole, error) {
+	serviceAccountRoles := []OpenidClientServiceAccountRole{
+		{
+			Id:                   roleId,
+			RealmId:              realm,
+			ContainerId:          clientId,
+			ServiceAccountUserId: serviceAccountUserId,
+		},
+	}
+	err := keycloakClient.get(fmt.Sprintf("/realms/%s/users/%s/role-mappings/clients/%s", realm, serviceAccountUserId, clientId), &serviceAccountRoles, nil)
+	if err != nil {
+		return nil, err
+	}
+	for _, serviceAccountRole := range serviceAccountRoles {
+		if serviceAccountRole.Id == roleId {
+			return &serviceAccountRole, nil
+		}
+	}
+	return &OpenidClientServiceAccountRole{}, nil
+}
diff --git a/keycloak/openid_full_name_protocol_mapper.go b/keycloak/openid_full_name_protocol_mapper.go
index fa6c7f0..a77b82a 100644
--- a/keycloak/openid_full_name_protocol_mapper.go
+++ b/keycloak/openid_full_name_protocol_mapper.go
@@ -63,7 +63,7 @@ func (protocolMapper *protocolMapper) convertToOpenIdFullNameProtocolMapper(real
 func (keycloakClient *KeycloakClient) GetOpenIdFullNameProtocolMapper(realmId, clientId, clientScopeId, mapperId string) (*OpenIdFullNameProtocolMapper, error) {
 	var protocolMapper *protocolMapper
 
-	err := keycloakClient.get(individualProtocolMapperPath(realmId, clientId, clientScopeId, mapperId), &protocolMapper)
+	err := keycloakClient.get(individualProtocolMapperPath(realmId, clientId, clientScopeId, mapperId), &protocolMapper, nil)
 	if err != nil {
 		return nil, err
 	}
@@ -72,13 +72,13 @@ func (keycloakClient *KeycloakClient) GetOpenIdFullNameProtocolMapper(realmId, c
 }
 
 func (keycloakClient *KeycloakClient) DeleteOpenIdFullNameProtocolMapper(realmId, clientId, clientScopeId, mapperId string) error {
-	return keycloakClient.delete(individualProtocolMapperPath(realmId, clientId, clientScopeId, mapperId))
+	return keycloakClient.delete(individualProtocolMapperPath(realmId, clientId, clientScopeId, mapperId), nil)
 }
 
 func (keycloakClient *KeycloakClient) NewOpenIdFullNameProtocolMapper(mapper *OpenIdFullNameProtocolMapper) error {
 	path := protocolMapperPath(mapper.RealmId, mapper.ClientId, mapper.ClientScopeId)
 
-	location, err := keycloakClient.post(path, mapper.convertToGenericProtocolMapper())
+	_, location, err := keycloakClient.post(path, mapper.convertToGenericProtocolMapper())
 	if err != nil {
 		return err
 	}
diff --git a/keycloak/openid_group_membership_protocol_mapper.go b/keycloak/openid_group_membership_protocol_mapper.go
index f5a0e90..256c297 100644
--- a/keycloak/openid_group_membership_protocol_mapper.go
+++ b/keycloak/openid_group_membership_protocol_mapper.go
@@ -75,7 +75,7 @@ func (protocolMapper *protocolMapper) convertToOpenIdGroupMembershipProtocolMapp
 func (keycloakClient *KeycloakClient) GetOpenIdGroupMembershipProtocolMapper(realmId, clientId, clientScopeId, mapperId string) (*OpenIdGroupMembershipProtocolMapper, error) {
 	var protocolMapper *protocolMapper
 
-	err := keycloakClient.get(individualProtocolMapperPath(realmId, clientId, clientScopeId, mapperId), &protocolMapper)
+	err := keycloakClient.get(individualProtocolMapperPath(realmId, clientId, clientScopeId, mapperId), &protocolMapper, nil)
 	if err != nil {
 		return nil, err
 	}
@@ -84,13 +84,13 @@ func (keycloakClient *KeycloakClient) GetOpenIdGroupMembershipProtocolMapper(rea
 }
 
 func (keycloakClient *KeycloakClient) DeleteOpenIdGroupMembershipProtocolMapper(realmId, clientId, clientScopeId, mapperId string) error {
-	return keycloakClient.delete(individualProtocolMapperPath(realmId, clientId, clientScopeId, mapperId))
+	return keycloakClient.delete(individualProtocolMapperPath(realmId, clientId, clientScopeId, mapperId), nil)
 }
 
 func (keycloakClient *KeycloakClient) NewOpenIdGroupMembershipProtocolMapper(mapper *OpenIdGroupMembershipProtocolMapper) error {
 	path := protocolMapperPath(mapper.RealmId, mapper.ClientId, mapper.ClientScopeId)
 
-	location, err := keycloakClient.post(path, mapper.convertToGenericProtocolMapper())
+	_, location, err := keycloakClient.post(path, mapper.convertToGenericProtocolMapper())
 	if err != nil {
 		return err
 	}
diff --git a/keycloak/openid_hardcoded_claim_protocol_mapper.go b/keycloak/openid_hardcoded_claim_protocol_mapper.go
index 31f879f..7a921a1 100644
--- a/keycloak/openid_hardcoded_claim_protocol_mapper.go
+++ b/keycloak/openid_hardcoded_claim_protocol_mapper.go
@@ -74,7 +74,7 @@ func (protocolMapper *protocolMapper) convertToOpenIdHardcodedClaimProtocolMappe
 func (keycloakClient *KeycloakClient) GetOpenIdHardcodedClaimProtocolMapper(realmId, clientId, clientScopeId, mapperId string) (*OpenIdHardcodedClaimProtocolMapper, error) {
 	var protocolMapper *protocolMapper
 
-	err := keycloakClient.get(individualProtocolMapperPath(realmId, clientId, clientScopeId, mapperId), &protocolMapper)
+	err := keycloakClient.get(individualProtocolMapperPath(realmId, clientId, clientScopeId, mapperId), &protocolMapper, nil)
 	if err != nil {
 		return nil, err
 	}
@@ -83,13 +83,13 @@ func (keycloakClient *KeycloakClient) GetOpenIdHardcodedClaimProtocolMapper(real
 }
 
 func (keycloakClient *KeycloakClient) DeleteOpenIdHardcodedClaimProtocolMapper(realmId, clientId, clientScopeId, mapperId string) error {
-	return keycloakClient.delete(individualProtocolMapperPath(realmId, clientId, clientScopeId, mapperId))
+	return keycloakClient.delete(individualProtocolMapperPath(realmId, clientId, clientScopeId, mapperId), nil)
 }
 
 func (keycloakClient *KeycloakClient) NewOpenIdHardcodedClaimProtocolMapper(mapper *OpenIdHardcodedClaimProtocolMapper) error {
 	path := protocolMapperPath(mapper.RealmId, mapper.ClientId, mapper.ClientScopeId)
 
-	location, err := keycloakClient.post(path, mapper.convertToGenericProtocolMapper())
+	_, location, err := keycloakClient.post(path, mapper.convertToGenericProtocolMapper())
 	if err != nil {
 		return err
 	}
diff --git a/keycloak/openid_user_attribute_protocol_mapper.go b/keycloak/openid_user_attribute_protocol_mapper.go
index 4615a99..ea9faf3 100644
--- a/keycloak/openid_user_attribute_protocol_mapper.go
+++ b/keycloak/openid_user_attribute_protocol_mapper.go
@@ -84,7 +84,7 @@ func (protocolMapper *protocolMapper) convertToOpenIdUserAttributeProtocolMapper
 func (keycloakClient *KeycloakClient) GetOpenIdUserAttributeProtocolMapper(realmId, clientId, clientScopeId, mapperId string) (*OpenIdUserAttributeProtocolMapper, error) {
 	var protocolMapper *protocolMapper
 
-	err := keycloakClient.get(individualProtocolMapperPath(realmId, clientId, clientScopeId, mapperId), &protocolMapper)
+	err := keycloakClient.get(individualProtocolMapperPath(realmId, clientId, clientScopeId, mapperId), &protocolMapper, nil)
 	if err != nil {
 		return nil, err
 	}
@@ -93,13 +93,13 @@ func (keycloakClient *KeycloakClient) GetOpenIdUserAttributeProtocolMapper(realm
 }
 
 func (keycloakClient *KeycloakClient) DeleteOpenIdUserAttributeProtocolMapper(realmId, clientId, clientScopeId, mapperId string) error {
-	return keycloakClient.delete(individualProtocolMapperPath(realmId, clientId, clientScopeId, mapperId))
+	return keycloakClient.delete(individualProtocolMapperPath(realmId, clientId, clientScopeId, mapperId), nil)
 }
 
 func (keycloakClient *KeycloakClient) NewOpenIdUserAttributeProtocolMapper(mapper *OpenIdUserAttributeProtocolMapper) error {
 	path := protocolMapperPath(mapper.RealmId, mapper.ClientId, mapper.ClientScopeId)
 
-	location, err := keycloakClient.post(path, mapper.convertToGenericProtocolMapper())
+	_, location, err := keycloakClient.post(path, mapper.convertToGenericProtocolMapper())
 	if err != nil {
 		return err
 	}
diff --git a/keycloak/openid_user_property_protocol_mapper.go b/keycloak/openid_user_property_protocol_mapper.go
index 522aaa6..9595bce 100644
--- a/keycloak/openid_user_property_protocol_mapper.go
+++ b/keycloak/openid_user_property_protocol_mapper.go
@@ -74,7 +74,7 @@ func (protocolMapper *protocolMapper) convertToOpenIdUserPropertyProtocolMapper(
 func (keycloakClient *KeycloakClient) GetOpenIdUserPropertyProtocolMapper(realmId, clientId, clientScopeId, mapperId string) (*OpenIdUserPropertyProtocolMapper, error) {
 	var protocolMapper *protocolMapper
 
-	err := keycloakClient.get(individualProtocolMapperPath(realmId, clientId, clientScopeId, mapperId), &protocolMapper)
+	err := keycloakClient.get(individualProtocolMapperPath(realmId, clientId, clientScopeId, mapperId), &protocolMapper, nil)
 	if err != nil {
 		return nil, err
 	}
@@ -83,13 +83,13 @@ func (keycloakClient *KeycloakClient) GetOpenIdUserPropertyProtocolMapper(realmI
 }
 
 func (keycloakClient *KeycloakClient) DeleteOpenIdUserPropertyProtocolMapper(realmId, clientId, clientScopeId, mapperId string) error {
-	return keycloakClient.delete(individualProtocolMapperPath(realmId, clientId, clientScopeId, mapperId))
+	return keycloakClient.delete(individualProtocolMapperPath(realmId, clientId, clientScopeId, mapperId), nil)
 }
 
 func (keycloakClient *KeycloakClient) NewOpenIdUserPropertyProtocolMapper(mapper *OpenIdUserPropertyProtocolMapper) error {
 	path := protocolMapperPath(mapper.RealmId, mapper.ClientId, mapper.ClientScopeId)
 
-	location, err := keycloakClient.post(path, mapper.convertToGenericProtocolMapper())
+	_, location, err := keycloakClient.post(path, mapper.convertToGenericProtocolMapper())
 	if err != nil {
 		return err
 	}
diff --git a/keycloak/protocol_mapper.go b/keycloak/protocol_mapper.go
index 5146547..92693e1 100644
--- a/keycloak/protocol_mapper.go
+++ b/keycloak/protocol_mapper.go
@@ -48,7 +48,7 @@ func individualProtocolMapperPath(realmId, clientId, clientScopeId, mapperId str
 func (keycloakClient *KeycloakClient) listGenericProtocolMappers(realmId, clientId, clientScopeId string) ([]*protocolMapper, error) {
 	var protocolMappers []*protocolMapper
 
-	err := keycloakClient.get(protocolMapperPath(realmId, clientId, clientScopeId), &protocolMappers)
+	err := keycloakClient.get(protocolMapperPath(realmId, clientId, clientScopeId), &protocolMappers, nil)
 	if err != nil {
 		return nil, err
 	}
diff --git a/keycloak/realm.go b/keycloak/realm.go
index 3671d8a..d45a2f6 100644
--- a/keycloak/realm.go
+++ b/keycloak/realm.go
@@ -43,7 +43,7 @@ type Realm struct {
 }
 
 func (keycloakClient *KeycloakClient) NewRealm(realm *Realm) error {
-	_, err := keycloakClient.post("/realms", realm)
+	_, _, err := keycloakClient.post("/realms", realm)
 
 	return err
 }
@@ -51,7 +51,7 @@ func (keycloakClient *KeycloakClient) NewRealm(realm *Realm) error {
 func (keycloakClient *KeycloakClient) GetRealm(id string) (*Realm, error) {
 	var realm Realm
 
-	err := keycloakClient.get(fmt.Sprintf("/realms/%s", id), &realm)
+	err := keycloakClient.get(fmt.Sprintf("/realms/%s", id), &realm, nil)
 	if err != nil {
 		return nil, err
 	}
@@ -64,10 +64,10 @@ func (keycloakClient *KeycloakClient) UpdateRealm(realm *Realm) error {
 }
 
 func (keycloakClient *KeycloakClient) DeleteRealm(id string) error {
-	err := keycloakClient.delete(fmt.Sprintf("/realms/%s", id))
+	err := keycloakClient.delete(fmt.Sprintf("/realms/%s", id), nil)
 	if err != nil {
 		// For whatever reason, this fails sometimes with a 500 during acceptance tests. try again
-		return keycloakClient.delete(fmt.Sprintf("/realms/%s", id))
+		return keycloakClient.delete(fmt.Sprintf("/realms/%s", id), nil)
 	}
 
 	return nil
diff --git a/keycloak/saml_client.go b/keycloak/saml_client.go
index be060a1..7350bb0 100644
--- a/keycloak/saml_client.go
+++ b/keycloak/saml_client.go
@@ -47,7 +47,7 @@ func (keycloakClient *KeycloakClient) NewSamlClient(client *SamlClient) error {
 	client.Protocol = "saml"
 	client.ClientAuthenticatorType = "client-secret"
 
-	location, err := keycloakClient.post(fmt.Sprintf("/realms/%s/clients", client.RealmId), client)
+	_, location, err := keycloakClient.post(fmt.Sprintf("/realms/%s/clients", client.RealmId), client)
 	if err != nil {
 		return err
 	}
@@ -60,7 +60,7 @@ func (keycloakClient *KeycloakClient) NewSamlClient(client *SamlClient) error {
 func (keycloakClient *KeycloakClient) GetSamlClient(realmId, id string) (*SamlClient, error) {
 	var client SamlClient
 
-	err := keycloakClient.get(fmt.Sprintf("/realms/%s/clients/%s", realmId, id), &client)
+	err := keycloakClient.get(fmt.Sprintf("/realms/%s/clients/%s", realmId, id), &client, nil)
 	if err != nil {
 		return nil, err
 	}
@@ -78,5 +78,5 @@ func (keycloakClient *KeycloakClient) UpdateSamlClient(client *SamlClient) error
 }
 
 func (keycloakClient *KeycloakClient) DeleteSamlClient(realmId, id string) error {
-	return keycloakClient.delete(fmt.Sprintf("/realms/%s/clients/%s", realmId, id))
+	return keycloakClient.delete(fmt.Sprintf("/realms/%s/clients/%s", realmId, id), nil)
 }
diff --git a/keycloak/saml_user_attribute_protocol_mapper.go b/keycloak/saml_user_attribute_protocol_mapper.go
index 0cbee86..5c760fd 100644
--- a/keycloak/saml_user_attribute_protocol_mapper.go
+++ b/keycloak/saml_user_attribute_protocol_mapper.go
@@ -50,7 +50,7 @@ func (protocolMapper *protocolMapper) convertToSamlUserAttributeProtocolMapper(r
 func (keycloakClient *KeycloakClient) GetSamlUserAttributeProtocolMapper(realmId, clientId, clientScopeId, mapperId string) (*SamlUserAttributeProtocolMapper, error) {
 	var protocolMapper *protocolMapper
 
-	err := keycloakClient.get(individualProtocolMapperPath(realmId, clientId, clientScopeId, mapperId), &protocolMapper)
+	err := keycloakClient.get(individualProtocolMapperPath(realmId, clientId, clientScopeId, mapperId), &protocolMapper, nil)
 	if err != nil {
 		return nil, err
 	}
@@ -59,13 +59,13 @@ func (keycloakClient *KeycloakClient) GetSamlUserAttributeProtocolMapper(realmId
 }
 
 func (keycloakClient *KeycloakClient) DeleteSamlUserAttributeProtocolMapper(realmId, clientId, clientScopeId, mapperId string) error {
-	return keycloakClient.delete(individualProtocolMapperPath(realmId, clientId, clientScopeId, mapperId))
+	return keycloakClient.delete(individualProtocolMapperPath(realmId, clientId, clientScopeId, mapperId), nil)
 }
 
 func (keycloakClient *KeycloakClient) NewSamlUserAttributeProtocolMapper(mapper *SamlUserAttributeProtocolMapper) error {
 	path := protocolMapperPath(mapper.RealmId, mapper.ClientId, mapper.ClientScopeId)
 
-	location, err := keycloakClient.post(path, mapper.convertToGenericProtocolMapper())
+	_, location, err := keycloakClient.post(path, mapper.convertToGenericProtocolMapper())
 	if err != nil {
 		return err
 	}
diff --git a/keycloak/saml_user_property_protocol_mapper.go b/keycloak/saml_user_property_protocol_mapper.go
index 194fede..3024ca8 100644
--- a/keycloak/saml_user_property_protocol_mapper.go
+++ b/keycloak/saml_user_property_protocol_mapper.go
@@ -50,7 +50,7 @@ func (protocolMapper *protocolMapper) convertToSamlUserPropertyProtocolMapper(re
 func (keycloakClient *KeycloakClient) GetSamlUserPropertyProtocolMapper(realmId, clientId, clientScopeId, mapperId string) (*SamlUserPropertyProtocolMapper, error) {
 	var protocolMapper *protocolMapper
 
-	err := keycloakClient.get(individualProtocolMapperPath(realmId, clientId, clientScopeId, mapperId), &protocolMapper)
+	err := keycloakClient.get(individualProtocolMapperPath(realmId, clientId, clientScopeId, mapperId), &protocolMapper, nil)
 	if err != nil {
 		return nil, err
 	}
@@ -59,13 +59,13 @@ func (keycloakClient *KeycloakClient) GetSamlUserPropertyProtocolMapper(realmId,
 }
 
 func (keycloakClient *KeycloakClient) DeleteSamlUserPropertyProtocolMapper(realmId, clientId, clientScopeId, mapperId string) error {
-	return keycloakClient.delete(individualProtocolMapperPath(realmId, clientId, clientScopeId, mapperId))
+	return keycloakClient.delete(individualProtocolMapperPath(realmId, clientId, clientScopeId, mapperId), nil)
 }
 
 func (keycloakClient *KeycloakClient) NewSamlUserPropertyProtocolMapper(mapper *SamlUserPropertyProtocolMapper) error {
 	path := protocolMapperPath(mapper.RealmId, mapper.ClientId, mapper.ClientScopeId)
 
-	location, err := keycloakClient.post(path, mapper.convertToGenericProtocolMapper())
+	_, location, err := keycloakClient.post(path, mapper.convertToGenericProtocolMapper())
 	if err != nil {
 		return err
 	}
diff --git a/keycloak/server_info.go b/keycloak/server_info.go
index b8a2a5c..48b7533 100644
--- a/keycloak/server_info.go
+++ b/keycloak/server_info.go
@@ -41,7 +41,7 @@ func (serverInfo *ServerInfo) ComponentTypeIsInstalled(componentType, componentT
 func (keycloakClient *KeycloakClient) GetServerInfo() (*ServerInfo, error) {
 	var serverInfo ServerInfo
 
-	err := keycloakClient.get("/serverinfo", &serverInfo)
+	err := keycloakClient.get("/serverinfo", &serverInfo, nil)
 	if err != nil {
 		return nil, err
 	}
diff --git a/keycloak/user.go b/keycloak/user.go
index 4c36b3e..8dbd9ce 100644
--- a/keycloak/user.go
+++ b/keycloak/user.go
@@ -2,18 +2,27 @@ package keycloak
 
 import (
 	"fmt"
-	"net/url"
 )
 
+type FederatedIdentity struct {
+	IdentityProvider string `json:"identityProvider"`
+	UserId           string `json:"userId"`
+	UserName         string `json:"userName"`
+}
+
+type FederatedIdentities []FederatedIdentity
+
 type User struct {
 	Id      string `json:"id,omitempty"`
 	RealmId string `json:"-"`
 
-	Username  string `json:"username"`
-	Email     string `json:"email"`
-	FirstName string `json:"firstName"`
-	LastName  string `json:"lastName"`
-	Enabled   bool   `json:"enabled"`
+	Username            string              `json:"username"`
+	Email               string              `json:"email"`
+	FirstName           string              `json:"firstName"`
+	LastName            string              `json:"lastName"`
+	Enabled             bool                `json:"enabled"`
+	Attributes          map[string][]string `json:"attributes"`
+	FederatedIdentities FederatedIdentities `json:"federatedIdentities"`
 }
 
 type PasswordCredentials struct {
@@ -23,7 +32,7 @@ type PasswordCredentials struct {
 }
 
 func (keycloakClient *KeycloakClient) NewUser(user *User) error {
-	location, err := keycloakClient.post(fmt.Sprintf("/realms/%s/users", user.RealmId), user)
+	_, location, err := keycloakClient.post(fmt.Sprintf("/realms/%s/users", user.RealmId), user)
 	if err != nil {
 		return err
 	}
@@ -50,7 +59,7 @@ func (keycloakClient *KeycloakClient) ResetUserPassword(realmId, userId string,
 func (keycloakClient *KeycloakClient) GetUser(realmId, id string) (*User, error) {
 	var user User
 
-	err := keycloakClient.get(fmt.Sprintf("/realms/%s/users/%s", realmId, id), &user)
+	err := keycloakClient.get(fmt.Sprintf("/realms/%s/users/%s", realmId, id), &user, nil)
 	if err != nil {
 		return nil, err
 	}
@@ -65,13 +74,17 @@ func (keycloakClient *KeycloakClient) UpdateUser(user *User) error {
 }
 
 func (keycloakClient *KeycloakClient) DeleteUser(realmId, id string) error {
-	return keycloakClient.delete(fmt.Sprintf("/realms/%s/users/%s", realmId, id))
+	return keycloakClient.delete(fmt.Sprintf("/realms/%s/users/%s", realmId, id), nil)
 }
 
 func (keycloakClient *KeycloakClient) GetUserByUsername(realmId, username string) (*User, error) {
 	var users []*User
 
-	err := keycloakClient.get(fmt.Sprintf("/realms/%s/users?username=%s", realmId, url.QueryEscape(username)), &users)
+	params := map[string]string{
+		"username": username,
+	}
+
+	err := keycloakClient.get(fmt.Sprintf("/realms/%s/users", realmId), &users, params)
 	if err != nil {
 		return nil, err
 	}
@@ -115,7 +128,7 @@ func (keycloakClient *KeycloakClient) AddUsersToGroup(realmId, groupId string, u
 }
 
 func (keycloakClient *KeycloakClient) RemoveUserFromGroup(user *User, groupId string) error {
-	return keycloakClient.delete(fmt.Sprintf("/realms/%s/users/%s/groups/%s", user.RealmId, user.Id, groupId))
+	return keycloakClient.delete(fmt.Sprintf("/realms/%s/users/%s/groups/%s", user.RealmId, user.Id, groupId), nil)
 }
 
 func (keycloakClient *KeycloakClient) RemoveUsersFromGroup(realmId, groupId string, usernames []interface{}) error {
diff --git a/provider/data_source_keycloak_openid_client.go b/provider/data_source_keycloak_openid_client.go
new file mode 100644
index 0000000..8450c4b
--- /dev/null
+++ b/provider/data_source_keycloak_openid_client.go
@@ -0,0 +1,116 @@
+package provider
+
+import (
+	"github.com/hashicorp/terraform/helper/schema"
+	"github.com/mrparkers/terraform-provider-keycloak/keycloak"
+)
+
+func dataSourceKeycloakOpenidClient() *schema.Resource {
+	return &schema.Resource{
+		Read: dataSourceKeycloakOpenidClientRead,
+
+		Schema: map[string]*schema.Schema{
+			"client_id": {
+				Type:     schema.TypeString,
+				Required: true,
+			},
+			"realm_id": {
+				Type:     schema.TypeString,
+				Required: true,
+			},
+			"name": {
+				Type:     schema.TypeString,
+				Computed: true,
+			},
+			"enabled": {
+				Type:     schema.TypeBool,
+				Computed: true,
+			},
+			"description": {
+				Type:     schema.TypeString,
+				Computed: true,
+			},
+			"access_type": {
+				Type:     schema.TypeString,
+				Computed: true,
+			},
+			"client_secret": {
+				Type:      schema.TypeString,
+				Computed:  true,
+				Sensitive: true,
+			},
+			"standard_flow_enabled": {
+				Type:     schema.TypeBool,
+				Computed: true,
+			},
+			"implicit_flow_enabled": {
+				Type:     schema.TypeBool,
+				Computed: true,
+			},
+			"direct_access_grants_enabled": {
+				Type:     schema.TypeBool,
+				Computed: true,
+			},
+			"valid_redirect_uris": {
+				Type:     schema.TypeSet,
+				Elem:     &schema.Schema{Type: schema.TypeString},
+				Set:      schema.HashString,
+				Computed: true,
+			},
+			"web_origins": {
+				Type:     schema.TypeSet,
+				Elem:     &schema.Schema{Type: schema.TypeString},
+				Set:      schema.HashString,
+				Computed: true,
+			},
+			"service_account_user_id": {
+				Type:     schema.TypeString,
+				Computed: true,
+			},
+			"service_accounts_enabled": {
+				Type:     schema.TypeBool,
+				Computed: true,
+			},
+			"resource_server_id": {
+				Type:     schema.TypeString,
+				Computed: true,
+			},
+			"authorization": {
+				Type:     schema.TypeSet,
+				Computed: true,
+				MaxItems: 1,
+				Elem: &schema.Resource{
+					Schema: map[string]*schema.Schema{
+						"policy_enforcement_mode": {
+							Type:     schema.TypeString,
+							Computed: true,
+						},
+						"allow_remote_resource_management": {
+							Type:     schema.TypeBool,
+							Computed: true,
+						},
+					},
+				},
+			},
+		},
+	}
+}
+
+func dataSourceKeycloakOpenidClientRead(data *schema.ResourceData, meta interface{}) error {
+	keycloakClient := meta.(*keycloak.KeycloakClient)
+
+	realmId := data.Get("realm_id").(string)
+	clientId := data.Get("client_id").(string)
+
+	client, err := keycloakClient.GetClientByName(realmId, clientId)
+	if err != nil {
+		return handleNotFoundError(err, data)
+	}
+
+	err = setOpenidClientData(keycloakClient, data, client)
+	if err != nil {
+		return err
+	}
+
+	return nil
+}
diff --git a/provider/data_source_keycloak_openid_client_authorization_policy.go b/provider/data_source_keycloak_openid_client_authorization_policy.go
new file mode 100644
index 0000000..4fb0622
--- /dev/null
+++ b/provider/data_source_keycloak_openid_client_authorization_policy.go
@@ -0,0 +1,90 @@
+package provider
+
+import (
+	"github.com/hashicorp/terraform/helper/schema"
+	"github.com/mrparkers/terraform-provider-keycloak/keycloak"
+)
+
+func dataSourceKeycloakOpenidClientAuthorizationPolicy() *schema.Resource {
+	return &schema.Resource{
+		Read: dataSourceKeycloakOpenidClientAuthorizationPolicyRead,
+
+		Schema: map[string]*schema.Schema{
+			"resource_server_id": {
+				Type:     schema.TypeString,
+				Required: true,
+			},
+			"realm_id": {
+				Type:     schema.TypeString,
+				Required: true,
+			},
+			"name": {
+				Type:     schema.TypeString,
+				Required: true,
+			},
+			"decision_strategy": {
+				Type:     schema.TypeString,
+				Computed: true,
+			},
+			"owner": {
+				Type:     schema.TypeString,
+				Computed: true,
+			},
+			"logic": {
+				Type:     schema.TypeString,
+				Computed: true,
+			},
+			"policies": {
+				Type:     schema.TypeSet,
+				Elem:     &schema.Schema{Type: schema.TypeString},
+				Computed: true,
+			},
+			"resources": {
+				Type:     schema.TypeSet,
+				Elem:     &schema.Schema{Type: schema.TypeString},
+				Computed: true,
+			},
+			"scopes": {
+				Type:     schema.TypeSet,
+				Elem:     &schema.Schema{Type: schema.TypeString},
+				Computed: true,
+			},
+			"type": {
+				Type:     schema.TypeString,
+				Computed: true,
+			},
+		},
+	}
+}
+
+func setOpenidClientAuthorizationPolicyData(data *schema.ResourceData, policy *keycloak.OpenidClientAuthorizationPolicy) {
+	data.SetId(policy.Id)
+
+	data.Set("resource_server_id", policy.ResourceServerId)
+	data.Set("realm_id", policy.RealmId)
+	data.Set("name", policy.Name)
+	data.Set("decision_strategy", policy.DecisionStrategy)
+	data.Set("owner", policy.Owner)
+	data.Set("logic", policy.Logic)
+	data.Set("policies", policy.Policies)
+	data.Set("resources", policy.Resources)
+	data.Set("scopes", policy.Scopes)
+	data.Set("type", policy.Type)
+}
+
+func dataSourceKeycloakOpenidClientAuthorizationPolicyRead(data *schema.ResourceData, meta interface{}) error {
+	keycloakClient := meta.(*keycloak.KeycloakClient)
+
+	realmId := data.Get("realm_id").(string)
+	resourceServerId := data.Get("resource_server_id").(string)
+	name := data.Get("name").(string)
+
+	client, err := keycloakClient.GetClientAuthorizationPolicyByName(realmId, resourceServerId, name)
+	if err != nil {
+		return handleNotFoundError(err, data)
+	}
+
+	setOpenidClientAuthorizationPolicyData(data, client)
+
+	return nil
+}
diff --git a/provider/provider.go b/provider/provider.go
index f5b0be7..2b3c28b 100644
--- a/provider/provider.go
+++ b/provider/provider.go
@@ -7,6 +7,10 @@ import (
 
 func KeycloakProvider() *schema.Provider {
 	return &schema.Provider{
+		DataSourcesMap: map[string]*schema.Resource{
+			"keycloak_openid_client":                      dataSourceKeycloakOpenidClient(),
+			"keycloak_openid_client_authorization_policy": dataSourceKeycloakOpenidClientAuthorizationPolicy(),
+		},
 		ResourcesMap: map[string]*schema.Resource{
 			"keycloak_realm":                                           resourceKeycloakRealm(),
 			"keycloak_group":                                           resourceKeycloakGroup(),
@@ -38,6 +42,10 @@ func KeycloakProvider() *schema.Provider {
 			"keycloak_user_template_importer_identity_provider_mapper": resourceKeycloakUserTemplateImporterIdentityProviderMapper(),
 			"keycloak_saml_identity_provider":                          resourceKeycloakSamlIdentityProvider(),
 			"keycloak_oidc_identity_provider":                          resourceKeycloakOidcIdentityProvider(),
+			"keycloak_openid_client_authorization_resource":            resourceKeycloakOpenidClientAuthorizationResource(),
+			"keycloak_openid_client_authorization_scope":               resourceKeycloakOpenidClientAuthorizationScope(),
+			"keycloak_openid_client_authorization_permission":          resourceKeycloakOpenidClientAuthorizationPermission(),
+			"keycloak_openid_client_service_account_role":              resourceKeycloakOpenidClientServiceAccountRole(),
 		},
 		Schema: map[string]*schema.Schema{
 			"client_id": {
diff --git a/provider/resource_keycloak_openid_client.go b/provider/resource_keycloak_openid_client.go
index 66fb7f8..4d07112 100644
--- a/provider/resource_keycloak_openid_client.go
+++ b/provider/resource_keycloak_openid_client.go
@@ -1,6 +1,7 @@
 package provider
 
 import (
+	"errors"
 	"fmt"
 	"github.com/hashicorp/terraform/helper/schema"
 	"github.com/hashicorp/terraform/helper/validation"
@@ -9,7 +10,8 @@ import (
 )
 
 var (
-	keycloakOpenidClientAccessTypes = []string{"CONFIDENTIAL", "PUBLIC", "BEARER-ONLY"}
+	keycloakOpenidClientAccessTypes                        = []string{"CONFIDENTIAL", "PUBLIC", "BEARER-ONLY"}
+	keycloakOpenidClientAuthorizationPolicyEnforcementMode = []string{"ENFORCING", "PERMISSIVE", "DISABLED"}
 )
 
 func resourceKeycloakOpenidClient() *schema.Resource {
@@ -71,11 +73,6 @@ func resourceKeycloakOpenidClient() *schema.Resource {
 				Optional: true,
 				Default:  false,
 			},
-			"service_accounts_enabled": {
-				Type:     schema.TypeBool,
-				Optional: true,
-				Default:  false,
-			},
 			"valid_redirect_uris": {
 				Type:     schema.TypeSet,
 				Elem:     &schema.Schema{Type: schema.TypeString},
@@ -88,11 +85,48 @@ func resourceKeycloakOpenidClient() *schema.Resource {
 				Set:      schema.HashString,
 				Optional: true,
 			},
+			"service_accounts_enabled": {
+				Type:     schema.TypeBool,
+				Optional: true,
+				Default:  false,
+			},
+			"service_account_user_id": {
+				Type:     schema.TypeString,
+				Computed: true,
+			},
+			"resource_server_id": {
+				Type:     schema.TypeString,
+				Computed: true,
+			},
+			"authorization": {
+				Type:     schema.TypeSet,
+				Optional: true,
+				MaxItems: 1,
+				Elem: &schema.Resource{
+					Schema: map[string]*schema.Schema{
+						"policy_enforcement_mode": {
+							Type:         schema.TypeString,
+							Required:     true,
+							ValidateFunc: validation.StringInSlice(keycloakOpenidClientAuthorizationPolicyEnforcementMode, false),
+						},
+						"allow_remote_resource_management": {
+							Type:     schema.TypeBool,
+							Optional: true,
+							Default:  false,
+						},
+						"keep_defaults": {
+							Type:     schema.TypeBool,
+							Optional: true,
+							Default:  false,
+						},
+					},
+				},
+			},
 		},
 	}
 }
 
-func getOpenidClientFromData(data *schema.ResourceData) *keycloak.OpenidClient {
+func getOpenidClientFromData(data *schema.ResourceData) (*keycloak.OpenidClient, error) {
 	validRedirectUris := make([]string, 0)
 	webOrigins := make([]string, 0)
 
@@ -124,6 +158,18 @@ func getOpenidClientFromData(data *schema.ResourceData) *keycloak.OpenidClient {
 		WebOrigins:                webOrigins,
 	}
 
+	if !openidClient.ImplicitFlowEnabled && !openidClient.StandardFlowEnabled {
+		if _, ok := data.GetOk("valid_redirect_uris"); ok {
+			return nil, errors.New("valid_redirect_uris cannot be set when standard or implicit flow is not enabled")
+		}
+	}
+
+	if !openidClient.ImplicitFlowEnabled && !openidClient.StandardFlowEnabled && !openidClient.DirectAccessGrantsEnabled {
+		if _, ok := data.GetOk("web_origins"); ok {
+			return nil, errors.New("web_origins cannot be set when standard or implicit flow is not enabled")
+		}
+	}
+
 	// access type
 	if accessType := data.Get("access_type").(string); accessType == "PUBLIC" {
 		openidClient.PublicClient = true
@@ -131,12 +177,31 @@ func getOpenidClientFromData(data *schema.ResourceData) *keycloak.OpenidClient {
 		openidClient.BearerOnly = true
 	}
 
-	return openidClient
+	if v, ok := data.GetOk("authorization"); ok {
+		openidClient.AuthorizationServicesEnabled = true
+		authorizationSettingsData := v.(*schema.Set).List()[0]
+		authorizationSettings := authorizationSettingsData.(map[string]interface{})
+		openidClient.AuthorizationSettings = &keycloak.OpenidClientAuthorizationSettings{
+			PolicyEnforcementMode:         authorizationSettings["policy_enforcement_mode"].(string),
+			AllowRemoteResourceManagement: authorizationSettings["allow_remote_resource_management"].(bool),
+			KeepDefaults:                  authorizationSettings["keep_defaults"].(bool),
+		}
+	} else {
+		openidClient.AuthorizationServicesEnabled = false
+	}
+	return openidClient, nil
 }
 
-func setOpenidClientData(data *schema.ResourceData, client *keycloak.OpenidClient) {
+func setOpenidClientData(keycloakClient *keycloak.KeycloakClient, data *schema.ResourceData, client *keycloak.OpenidClient) error {
+	var serviceAccountUserId string
+	if client.ServiceAccountsEnabled {
+		serviceAccountUser, err := keycloakClient.GetOpenidClientServiceAccountUserId(client.RealmId, client.Id)
+		if err != nil {
+			return err
+		}
+		serviceAccountUserId = serviceAccountUser.Id
+	}
 	data.SetId(client.Id)
-
 	data.Set("client_id", client.ClientId)
 	data.Set("realm_id", client.RealmId)
 	data.Set("name", client.Name)
@@ -149,6 +214,15 @@ func setOpenidClientData(data *schema.ResourceData, client *keycloak.OpenidClien
 	data.Set("service_accounts_enabled", client.ServiceAccountsEnabled)
 	data.Set("valid_redirect_uris", client.ValidRedirectUris)
 	data.Set("web_origins", client.WebOrigins)
+	data.Set("authorization_services_enabled", client.AuthorizationServicesEnabled)
+
+	if client.AuthorizationServicesEnabled {
+		data.Set("resource_server_id", client.Id)
+	}
+
+	if client.ServiceAccountsEnabled {
+		data.Set("service_account_user_id", serviceAccountUserId)
+	}
 
 	// access type
 	if client.PublicClient {
@@ -158,14 +232,18 @@ func setOpenidClientData(data *schema.ResourceData, client *keycloak.OpenidClien
 	} else {
 		data.Set("access_type", "CONFIDENTIAL")
 	}
+	return nil
 }
 
 func resourceKeycloakOpenidClientCreate(data *schema.ResourceData, meta interface{}) error {
 	keycloakClient := meta.(*keycloak.KeycloakClient)
 
-	client := getOpenidClientFromData(data)
+	client, err := getOpenidClientFromData(data)
+	if err != nil {
+		return err
+	}
 
-	err := keycloakClient.ValidateOpenidClient(client)
+	err = keycloakClient.ValidateOpenidClient(client)
 	if err != nil {
 		return err
 	}
@@ -175,7 +253,10 @@ func resourceKeycloakOpenidClientCreate(data *schema.ResourceData, meta interfac
 		return err
 	}
 
-	setOpenidClientData(data, client)
+	err = setOpenidClientData(keycloakClient, data, client)
+	if err != nil {
+		return err
+	}
 
 	return resourceKeycloakOpenidClientRead(data, meta)
 }
@@ -191,7 +272,10 @@ func resourceKeycloakOpenidClientRead(data *schema.ResourceData, meta interface{
 		return handleNotFoundError(err, data)
 	}
 
-	setOpenidClientData(data, client)
+	err = setOpenidClientData(keycloakClient, data, client)
+	if err != nil {
+		return err
+	}
 
 	return nil
 }
@@ -199,9 +283,12 @@ func resourceKeycloakOpenidClientRead(data *schema.ResourceData, meta interface{
 func resourceKeycloakOpenidClientUpdate(data *schema.ResourceData, meta interface{}) error {
 	keycloakClient := meta.(*keycloak.KeycloakClient)
 
-	client := getOpenidClientFromData(data)
+	client, err := getOpenidClientFromData(data)
+	if err != nil {
+		return err
+	}
 
-	err := keycloakClient.ValidateOpenidClient(client)
+	err = keycloakClient.ValidateOpenidClient(client)
 	if err != nil {
 		return err
 	}
@@ -211,7 +298,10 @@ func resourceKeycloakOpenidClientUpdate(data *schema.ResourceData, meta interfac
 		return err
 	}
 
-	setOpenidClientData(data, client)
+	err = setOpenidClientData(keycloakClient, data, client)
+	if err != nil {
+		return err
+	}
 
 	return nil
 }
diff --git a/provider/resource_keycloak_openid_client_authorization_permission.go b/provider/resource_keycloak_openid_client_authorization_permission.go
new file mode 100644
index 0000000..0ce9f43
--- /dev/null
+++ b/provider/resource_keycloak_openid_client_authorization_permission.go
@@ -0,0 +1,176 @@
+package provider
+
+import (
+	"fmt"
+	"github.com/hashicorp/terraform/helper/schema"
+	"github.com/hashicorp/terraform/helper/validation"
+	"github.com/mrparkers/terraform-provider-keycloak/keycloak"
+	"strings"
+)
+
+var (
+	keycloakOpenidClientResourcePermissionDecisionStrategies = []string{"UNANIMOUS", "AFFIRMATIVE", "CONSENSUS"}
+	keycloakOpenidClientPermissionTypes                      = []string{"resource", "scope"}
+)
+
+func resourceKeycloakOpenidClientAuthorizationPermission() *schema.Resource {
+	return &schema.Resource{
+		Create: resourceKeycloakOpenidClientAuthorizationPermissionCreate,
+		Read:   resourceKeycloakOpenidClientAuthorizationPermissionRead,
+		Delete: resourceKeycloakOpenidClientAuthorizationPermissionDelete,
+		Update: resourceKeycloakOpenidClientAuthorizationPermissionUpdate,
+		Importer: &schema.ResourceImporter{
+			State: resourceKeycloakOpenidClientAuthorizationPermissionImport,
+		},
+		Schema: map[string]*schema.Schema{
+			"resource_server_id": {
+				Type:     schema.TypeString,
+				Required: true,
+				ForceNew: true,
+			},
+			"realm_id": {
+				Type:     schema.TypeString,
+				Required: true,
+				ForceNew: true,
+			},
+			"name": {
+				Type:     schema.TypeString,
+				Required: true,
+			},
+			"description": {
+				Type:     schema.TypeString,
+				Optional: true,
+			},
+			"decision_strategy": {
+				Type:         schema.TypeString,
+				Optional:     true,
+				ValidateFunc: validation.StringInSlice(keycloakOpenidClientResourcePermissionDecisionStrategies, false),
+				Default:      "UNANIMOUS",
+			},
+			"policies": {
+				Type:     schema.TypeSet,
+				Elem:     &schema.Schema{Type: schema.TypeString},
+				Optional: true,
+			},
+			"resources": {
+				Type:     schema.TypeSet,
+				Elem:     &schema.Schema{Type: schema.TypeString},
+				Optional: true,
+			},
+			"type": {
+				Type:         schema.TypeString,
+				Optional:     true,
+				Default:      "resource",
+				ValidateFunc: validation.StringInSlice(keycloakOpenidClientPermissionTypes, false),
+			},
+		},
+	}
+}
+
+func getOpenidClientAuthorizationPermissionFromData(data *schema.ResourceData) *keycloak.OpenidClientAuthorizationPermission {
+	var policies []string
+	var resources []string
+	if v, ok := data.GetOk("resources"); ok {
+		for _, resource := range v.(*schema.Set).List() {
+			resources = append(resources, resource.(string))
+		}
+	}
+	if v, ok := data.GetOk("policies"); ok {
+		for _, policy := range v.(*schema.Set).List() {
+			policies = append(policies, policy.(string))
+		}
+	}
+	permission := keycloak.OpenidClientAuthorizationPermission{
+		Id:               data.Id(),
+		ResourceServerId: data.Get("resource_server_id").(string),
+		RealmId:          data.Get("realm_id").(string),
+		Description:      data.Get("description").(string),
+		Name:             data.Get("name").(string),
+		DecisionStrategy: data.Get("decision_strategy").(string),
+		Type:             data.Get("type").(string),
+		Policies:         policies,
+		Resources:        resources,
+	}
+	return &permission
+}
+
+func setOpenidClientAuthorizationPermissionData(data *schema.ResourceData, permission *keycloak.OpenidClientAuthorizationPermission) {
+	data.SetId(permission.Id)
+	data.Set("resource_server_id", permission.ResourceServerId)
+	data.Set("realm_id", permission.RealmId)
+	data.Set("description", permission.Description)
+	data.Set("name", permission.Name)
+	data.Set("decision_strategy", permission.DecisionStrategy)
+	data.Set("type", permission.Type)
+	data.Set("policies", permission.Policies)
+	data.Set("resources", permission.Resources)
+}
+
+func resourceKeycloakOpenidClientAuthorizationPermissionCreate(data *schema.ResourceData, meta interface{}) error {
+	keycloakClient := meta.(*keycloak.KeycloakClient)
+
+	permission := getOpenidClientAuthorizationPermissionFromData(data)
+
+	err := keycloakClient.NewOpenidClientAuthorizationPermission(permission)
+	if err != nil {
+		return err
+	}
+
+	setOpenidClientAuthorizationPermissionData(data, permission)
+
+	return resourceKeycloakOpenidClientAuthorizationPermissionRead(data, meta)
+}
+
+func resourceKeycloakOpenidClientAuthorizationPermissionRead(data *schema.ResourceData, meta interface{}) error {
+	keycloakClient := meta.(*keycloak.KeycloakClient)
+
+	realmId := data.Get("realm_id").(string)
+	resourceServerId := data.Get("resource_server_id").(string)
+	id := data.Id()
+
+	permission, err := keycloakClient.GetOpenidClientAuthorizationPermission(realmId, resourceServerId, id)
+	if err != nil {
+		return handleNotFoundError(err, data)
+	}
+
+	setOpenidClientAuthorizationPermissionData(data, permission)
+
+	return nil
+}
+
+func resourceKeycloakOpenidClientAuthorizationPermissionUpdate(data *schema.ResourceData, meta interface{}) error {
+	keycloakClient := meta.(*keycloak.KeycloakClient)
+
+	permission := getOpenidClientAuthorizationPermissionFromData(data)
+
+	err := keycloakClient.UpdateOpenidClientAuthorizationPermission(permission)
+	if err != nil {
+		return err
+	}
+
+	setOpenidClientAuthorizationPermissionData(data, permission)
+
+	return nil
+}
+
+func resourceKeycloakOpenidClientAuthorizationPermissionDelete(data *schema.ResourceData, meta interface{}) error {
+	keycloakClient := meta.(*keycloak.KeycloakClient)
+
+	realmId := data.Get("realm_id").(string)
+	resourceServerId := data.Get("resource_server_id").(string)
+	id := data.Id()
+
+	return keycloakClient.DeleteOpenidClientAuthorizationPermission(realmId, resourceServerId, id)
+}
+
+func resourceKeycloakOpenidClientAuthorizationPermissionImport(d *schema.ResourceData, _ interface{}) ([]*schema.ResourceData, error) {
+	parts := strings.Split(d.Id(), "/")
+	if len(parts) != 3 {
+		return nil, fmt.Errorf("Invalid import. Supported import formats: {{realmId}}/{{resourceServerId}}/{{permissionId}}")
+	}
+	d.Set("realm_id", parts[0])
+	d.Set("resource_server_id", parts[1])
+	d.SetId(parts[3])
+
+	return []*schema.ResourceData{d}, nil
+}
diff --git a/provider/resource_keycloak_openid_client_authorization_resource.go b/provider/resource_keycloak_openid_client_authorization_resource.go
new file mode 100644
index 0000000..e7aad5d
--- /dev/null
+++ b/provider/resource_keycloak_openid_client_authorization_resource.go
@@ -0,0 +1,191 @@
+package provider
+
+import (
+	"fmt"
+	"github.com/hashicorp/terraform/helper/schema"
+	"github.com/mrparkers/terraform-provider-keycloak/keycloak"
+	"strings"
+)
+
+func resourceKeycloakOpenidClientAuthorizationResource() *schema.Resource {
+	return &schema.Resource{
+		Create: resourceKeycloakOpenidClientAuthorizationResourceCreate,
+		Read:   resourceKeycloakOpenidClientAuthorizationResourceRead,
+		Delete: resourceKeycloakOpenidClientAuthorizationResourceDelete,
+		Update: resourceKeycloakOpenidClientAuthorizationResourceUpdate,
+		Importer: &schema.ResourceImporter{
+			State: resourceKeycloakOpenidClientAuthorizationResourceImport,
+		},
+		Schema: map[string]*schema.Schema{
+			"resource_server_id": {
+				Type:     schema.TypeString,
+				Required: true,
+				ForceNew: true,
+			},
+			"realm_id": {
+				Type:     schema.TypeString,
+				Required: true,
+				ForceNew: true,
+			},
+			"name": {
+				Type:     schema.TypeString,
+				Required: true,
+			},
+			"display_name": {
+				Type:     schema.TypeString,
+				Optional: true,
+			},
+			"uris": {
+				Type:     schema.TypeSet,
+				Elem:     &schema.Schema{Type: schema.TypeString},
+				Optional: true,
+			},
+			"icon_uri": {
+				Type:     schema.TypeString,
+				Optional: true,
+			},
+			"owner_managed_access": {
+				Type:     schema.TypeBool,
+				Optional: true,
+				Default:  false,
+			},
+			"scopes": {
+				Type:     schema.TypeSet,
+				Elem:     &schema.Schema{Type: schema.TypeString},
+				Optional: true,
+			},
+			"type": {
+				Type:     schema.TypeString,
+				Optional: true,
+			},
+			"attributes": {
+				Type:     schema.TypeMap,
+				Optional: true,
+			},
+		},
+	}
+}
+
+func getOpenidClientAuthorizationResourceFromData(data *schema.ResourceData) *keycloak.OpenidClientAuthorizationResource {
+	var uris []string
+	var scopes []keycloak.OpenidClientAuthorizationScope
+	attributes := map[string][]string{}
+	if v, ok := data.GetOk("uris"); ok {
+		for _, uri := range v.(*schema.Set).List() {
+			uris = append(uris, uri.(string))
+		}
+	}
+	if v, ok := data.GetOk("scopes"); ok {
+		for _, scope := range v.(*schema.Set).List() {
+			scopes = append(scopes, keycloak.OpenidClientAuthorizationScope{
+				Name: scope.(string),
+			})
+		}
+	}
+	if v, ok := data.GetOk("attributes"); ok {
+		for key, value := range v.(map[string]interface{}) {
+			attributes[key] = strings.Split(value.(string), ",")
+		}
+	}
+	resource := keycloak.OpenidClientAuthorizationResource{
+		Id:                 data.Id(),
+		DisplayName:        data.Get("display_name").(string),
+		Name:               data.Get("name").(string),
+		IconUri:            data.Get("icon_uri").(string),
+		OwnerManagedAccess: data.Get("owner_managed_access").(bool),
+		Type:               data.Get("type").(string),
+		ResourceServerId:   data.Get("resource_server_id").(string),
+		RealmId:            data.Get("realm_id").(string),
+		Uris:               uris,
+		Scopes:             scopes,
+		Attributes:         attributes,
+	}
+	return &resource
+}
+
+func setOpenidClientAuthorizationResourceData(data *schema.ResourceData, resource *keycloak.OpenidClientAuthorizationResource) {
+	scopes := []string{}
+	for _, scope := range resource.Scopes {
+		scopes = append(scopes, scope.Name)
+	}
+	data.SetId(resource.Id)
+	data.Set("resource_server_id", resource.ResourceServerId)
+	data.Set("realm_id", resource.RealmId)
+	data.Set("display_name", resource.DisplayName)
+	data.Set("name", resource.Name)
+	data.Set("icon_uri", resource.IconUri)
+	data.Set("owner_managed_access", resource.OwnerManagedAccess)
+	data.Set("type", resource.Type)
+	data.Set("uris", resource.Uris)
+	data.Set("attributes", resource.Attributes)
+	data.Set("scopes", scopes)
+}
+
+func resourceKeycloakOpenidClientAuthorizationResourceCreate(data *schema.ResourceData, meta interface{}) error {
+	keycloakClient := meta.(*keycloak.KeycloakClient)
+
+	resource := getOpenidClientAuthorizationResourceFromData(data)
+
+	err := keycloakClient.NewOpenidClientAuthorizationResource(resource)
+	if err != nil {
+		return err
+	}
+
+	setOpenidClientAuthorizationResourceData(data, resource)
+
+	return resourceKeycloakOpenidClientAuthorizationResourceRead(data, meta)
+}
+
+func resourceKeycloakOpenidClientAuthorizationResourceRead(data *schema.ResourceData, meta interface{}) error {
+	keycloakClient := meta.(*keycloak.KeycloakClient)
+
+	realmId := data.Get("realm_id").(string)
+	resourceServerId := data.Get("resource_server_id").(string)
+	id := data.Id()
+
+	resource, err := keycloakClient.GetOpenidClientAuthorizationResource(realmId, resourceServerId, id)
+	if err != nil {
+		return handleNotFoundError(err, data)
+	}
+
+	setOpenidClientAuthorizationResourceData(data, resource)
+
+	return nil
+}
+
+func resourceKeycloakOpenidClientAuthorizationResourceUpdate(data *schema.ResourceData, meta interface{}) error {
+	keycloakClient := meta.(*keycloak.KeycloakClient)
+
+	resource := getOpenidClientAuthorizationResourceFromData(data)
+
+	err := keycloakClient.UpdateOpenidClientAuthorizationResource(resource)
+	if err != nil {
+		return err
+	}
+
+	setOpenidClientAuthorizationResourceData(data, resource)
+
+	return nil
+}
+
+func resourceKeycloakOpenidClientAuthorizationResourceDelete(data *schema.ResourceData, meta interface{}) error {
+	keycloakClient := meta.(*keycloak.KeycloakClient)
+
+	realmId := data.Get("realm_id").(string)
+	resourceServerId := data.Get("resource_server_id").(string)
+	id := data.Id()
+
+	return keycloakClient.DeleteOpenidClientAuthorizationResource(realmId, resourceServerId, id)
+}
+
+func resourceKeycloakOpenidClientAuthorizationResourceImport(d *schema.ResourceData, _ interface{}) ([]*schema.ResourceData, error) {
+	parts := strings.Split(d.Id(), "/")
+	if len(parts) != 3 {
+		return nil, fmt.Errorf("Invalid import. Supported import formats: {{realmId}}/{{resourceServerId}}/{{authorizationResourceId}}")
+	}
+	d.Set("realm_id", parts[0])
+	d.Set("resource_server_id", parts[1])
+	d.SetId(parts[3])
+
+	return []*schema.ResourceData{d}, nil
+}
diff --git a/provider/resource_keycloak_openid_client_authorization_scope.go b/provider/resource_keycloak_openid_client_authorization_scope.go
new file mode 100644
index 0000000..723e29c
--- /dev/null
+++ b/provider/resource_keycloak_openid_client_authorization_scope.go
@@ -0,0 +1,134 @@
+package provider
+
+import (
+	"fmt"
+	"github.com/hashicorp/terraform/helper/schema"
+	"github.com/mrparkers/terraform-provider-keycloak/keycloak"
+	"strings"
+)
+
+func resourceKeycloakOpenidClientAuthorizationScope() *schema.Resource {
+	return &schema.Resource{
+		Create: resourceKeycloakOpenidClientAuthorizationScopeCreate,
+		Read:   resourceKeycloakOpenidClientAuthorizationScopeRead,
+		Delete: resourceKeycloakOpenidClientAuthorizationScopeDelete,
+		Update: resourceKeycloakOpenidClientAuthorizationScopeUpdate,
+		Importer: &schema.ResourceImporter{
+			State: resourceKeycloakOpenidClientAuthorizationScopeImport,
+		},
+		Schema: map[string]*schema.Schema{
+			"resource_server_id": {
+				Type:     schema.TypeString,
+				Required: true,
+				ForceNew: true,
+			},
+			"realm_id": {
+				Type:     schema.TypeString,
+				Required: true,
+				ForceNew: true,
+			},
+			"name": {
+				Type:     schema.TypeString,
+				Required: true,
+			},
+			"display_name": {
+				Type:     schema.TypeString,
+				Optional: true,
+			},
+			"icon_uri": {
+				Type:     schema.TypeString,
+				Optional: true,
+			},
+		},
+	}
+}
+
+func getOpenidClientAuthorizationScopeFromData(data *schema.ResourceData) *keycloak.OpenidClientAuthorizationScope {
+	scope := keycloak.OpenidClientAuthorizationScope{
+		DisplayName:      data.Get("display_name").(string),
+		Name:             data.Get("name").(string),
+		IconUri:          data.Get("icon_uri").(string),
+		Id:               data.Id(),
+		ResourceServerId: data.Get("resource_server_id").(string),
+		RealmId:          data.Get("realm_id").(string),
+	}
+	return &scope
+}
+
+func setOpenidClientAuthorizationScopeData(data *schema.ResourceData, scope *keycloak.OpenidClientAuthorizationScope) {
+	data.SetId(scope.Id)
+	data.Set("resource_server_id", scope.ResourceServerId)
+	data.Set("realm_id", scope.RealmId)
+	data.Set("display_name", scope.DisplayName)
+	data.Set("name", scope.Name)
+	data.Set("icon_uri", scope.IconUri)
+}
+
+func resourceKeycloakOpenidClientAuthorizationScopeCreate(data *schema.ResourceData, meta interface{}) error {
+	keycloakClient := meta.(*keycloak.KeycloakClient)
+
+	scope := getOpenidClientAuthorizationScopeFromData(data)
+
+	err := keycloakClient.NewOpenidClientAuthorizationScope(scope)
+	if err != nil {
+		return err
+	}
+
+	setOpenidClientAuthorizationScopeData(data, scope)
+
+	return resourceKeycloakOpenidClientAuthorizationScopeRead(data, meta)
+}
+
+func resourceKeycloakOpenidClientAuthorizationScopeRead(data *schema.ResourceData, meta interface{}) error {
+	keycloakClient := meta.(*keycloak.KeycloakClient)
+
+	realmId := data.Get("realm_id").(string)
+	resourceServerId := data.Get("resource_server_id").(string)
+	id := data.Id()
+
+	scope, err := keycloakClient.GetOpenidClientAuthorizationScope(realmId, resourceServerId, id)
+	if err != nil {
+		return handleNotFoundError(err, data)
+	}
+
+	setOpenidClientAuthorizationScopeData(data, scope)
+
+	return nil
+}
+
+func resourceKeycloakOpenidClientAuthorizationScopeUpdate(data *schema.ResourceData, meta interface{}) error {
+	keycloakClient := meta.(*keycloak.KeycloakClient)
+
+	scope := getOpenidClientAuthorizationScopeFromData(data)
+
+	err := keycloakClient.UpdateOpenidClientAuthorizationScope(scope)
+	if err != nil {
+		return err
+	}
+
+	setOpenidClientAuthorizationScopeData(data, scope)
+
+	return nil
+}
+
+func resourceKeycloakOpenidClientAuthorizationScopeDelete(data *schema.ResourceData, meta interface{}) error {
+	keycloakClient := meta.(*keycloak.KeycloakClient)
+
+	realmId := data.Get("realm_id").(string)
+	resourceServerId := data.Get("resource_server_id").(string)
+	id := data.Id()
+
+	return keycloakClient.DeleteOpenidClientAuthorizationScope(realmId, resourceServerId, id)
+}
+
+func resourceKeycloakOpenidClientAuthorizationScopeImport(d *schema.ResourceData, _ interface{}) ([]*schema.ResourceData, error) {
+	parts := strings.Split(d.Id(), "/")
+	if len(parts) != 3 {
+		return nil, fmt.Errorf("Invalid import. Supported import formats: {{realmId}}/{{resourceServerId}}/{{authorizationScopeId}}")
+	}
+	d.Set("realm_id", parts[0])
+	d.Set("resource_server_id", parts[1])
+	d.SetId(parts[3])
+
+	return []*schema.ResourceData{d}, nil
+}
diff --git a/provider/resource_keycloak_openid_client_service_account_role.go b/provider/resource_keycloak_openid_client_service_account_role.go
new file mode 100644
index 0000000..75be439
--- /dev/null
+++ b/provider/resource_keycloak_openid_client_service_account_role.go
@@ -0,0 +1,112 @@
+package provider
+
+import (
+	"fmt"
+	"github.com/hashicorp/terraform/helper/schema"
+	"github.com/mrparkers/terraform-provider-keycloak/keycloak"
+	"strings"
+)
+
+func resourceKeycloakOpenidClientServiceAccountRole() *schema.Resource {
+	return &schema.Resource{
+		Create: resourceKeycloakOpenidClientServiceAccountRoleCreate,
+		Read:   resourceKeycloakOpenidClientServiceAccountRoleRead,
+		Delete: resourceKeycloakOpenidClientServiceAccountRoleDelete,
+		Importer: &schema.ResourceImporter{
+			State: resourceKeycloakOpenidClientServiceAccountRoleImport,
+		},
+		Schema: map[string]*schema.Schema{
+			"service_account_user_id": {
+				Type:     schema.TypeString,
+				Required: true,
+				ForceNew: true,
+			},
+			"realm_id": {
+				Type:     schema.TypeString,
+				Required: true,
+				ForceNew: true,
+			},
+			"client_id": {
+				Type:     schema.TypeString,
+				Required: true,
+				ForceNew: true,
+			},
+			"role": {
+				Type:     schema.TypeString,
+				Required: true,
+				ForceNew: true,
+			},
+		},
+	}
+}
+
+func getOpenidClientServiceAccountRoleFromData(data *schema.ResourceData) *keycloak.OpenidClientServiceAccountRole {
+	return &keycloak.OpenidClientServiceAccountRole{
+		Id:                   data.Id(),
+		ContainerId:          data.Get("client_id").(string),
+		Name:                 data.Get("role").(string),
+		RealmId:              data.Get("realm_id").(string),
+		ServiceAccountUserId: data.Get("service_account_user_id").(string),
+	}
+}
+
+func setOpenidClientServiceAccountRoleData(data *schema.ResourceData, serviceAccountRole *keycloak.OpenidClientServiceAccountRole) {
+	data.SetId(serviceAccountRole.Id)
+	data.Set("realm_id", serviceAccountRole.RealmId)
+	data.Set("client_id", serviceAccountRole.ContainerId)
+	data.Set("service_account_user_id", serviceAccountRole.ServiceAccountUserId)
+	data.Set("role", serviceAccountRole.Name)
+}
+
+func resourceKeycloakOpenidClientServiceAccountRoleCreate(data *schema.ResourceData, meta interface{}) error {
+	keycloakClient := meta.(*keycloak.KeycloakClient)
+	serviceAccountRole := getOpenidClientServiceAccountRoleFromData(data)
+	err := keycloakClient.NewOpenidClientServiceAccountRole(serviceAccountRole)
+	if err != nil {
+		return err
+	}
+	setOpenidClientServiceAccountRoleData(data, serviceAccountRole)
+	return resourceKeycloakOpenidClientServiceAccountRoleRead(data, meta)
+}
+
+func resourceKeycloakOpenidClientServiceAccountRoleRead(data *schema.ResourceData, meta interface{}) error {
+	keycloakClient := meta.(*keycloak.KeycloakClient)
+
+	realmId := data.Get("realm_id").(string)
+	serviceAccountUserId := data.Get("service_account_user_id").(string)
+	clientId := data.Get("client_id").(string)
+	id := data.Id()
+
+	serviceAccountRole, err := keycloakClient.GetOpenidClientServiceAccountRole(realmId, serviceAccountUserId, clientId, id)
+	if err != nil {
+		return handleNotFoundError(err, data)
+	}
+
+	setOpenidClientServiceAccountRoleData(data, serviceAccountRole)
+
+	return nil
+}
+
+func resourceKeycloakOpenidClientServiceAccountRoleDelete(data *schema.ResourceData, meta interface{}) error {
+	keycloakClient := meta.(*keycloak.KeycloakClient)
+
+	realmId := data.Get("realm_id").(string)
+	serviceAccountUserId := data.Get("service_account_user_id").(string)
+	clientId := data.Get("client_id").(string)
+	id := data.Id()
+
+	return keycloakClient.DeleteOpenidClientServiceAccountRole(realmId, serviceAccountUserId, clientId, id)
+}
+
+func resourceKeycloakOpenidClientServiceAccountRoleImport(d *schema.ResourceData, _ interface{}) ([]*schema.ResourceData, error) {
+	parts := strings.Split(d.Id(), "/")
+	if len(parts) != 3 {
+		return nil, fmt.Errorf("Invalid import. Supported import formats: {{realmId}}/{{serviceAccountUserId}}/{{clientId}}/{{role}}")
+	}
+	d.Set("realm_id", parts[0])
+	d.Set("service_account_user_id", parts[1])
+	d.Set("client_id", parts[2])
+	d.SetId(parts[3])
+
+	return []*schema.ResourceData{d}, nil
+}
diff --git a/provider/resource_keycloak_user.go b/provider/resource_keycloak_user.go
index da396b7..e9db4ed 100644
--- a/provider/resource_keycloak_user.go
+++ b/provider/resource_keycloak_user.go
@@ -49,6 +49,30 @@ func resourceKeycloakUser() *schema.Resource {
 				Type:     schema.TypeString,
 				Optional: true,
 			},
+			"attributes": {
+				Type:     schema.TypeMap,
+				Optional: true,
+			},
+			"federated_identity": {
+				Type:     schema.TypeSet,
+				Optional: true,
+				Elem: &schema.Resource{
+					Schema: map[string]*schema.Schema{
+						"identity_provider": {
+							Type:     schema.TypeString,
+							Required: true,
+						},
+						"user_id": {
+							Type:     schema.TypeString,
+							Required: true,
+						},
+						"user_name": {
+							Type:     schema.TypeString,
+							Required: true,
+						},
+					},
+				},
+			},
 			"initial_password": {
 				Type:             schema.TypeList,
 				Optional:         true,
@@ -83,15 +107,44 @@ func onlyDiffOnCreate(_, _, _ string, d *schema.ResourceData) bool {
 }
 
 func mapFromDataToUser(data *schema.ResourceData) *keycloak.User {
+	attributes := map[string][]string{}
+	if v, ok := data.GetOk("attributes"); ok {
+		for key, value := range v.(map[string]interface{}) {
+			attributes[key] = strings.Split(value.(string), ",")
+		}
+	}
+
+	federatedIdentities := &keycloak.FederatedIdentities{}
+
+	if v, ok := data.GetOk("federated_identity"); ok {
+		federatedIdentities = getUserFederatedIdentitiesFromData(v.(*schema.Set).List())
+	}
+
 	return &keycloak.User{
-		Id:        data.Id(),
-		RealmId:   data.Get("realm_id").(string),
-		Username:  data.Get("username").(string),
-		Email:     data.Get("email").(string),
-		FirstName: data.Get("first_name").(string),
-		LastName:  data.Get("last_name").(string),
-		Enabled:   data.Get("enabled").(bool),
+		Id:                  data.Id(),
+		RealmId:             data.Get("realm_id").(string),
+		Username:            data.Get("username").(string),
+		Email:               data.Get("email").(string),
+		FirstName:           data.Get("first_name").(string),
+		LastName:            data.Get("last_name").(string),
+		Enabled:             data.Get("enabled").(bool),
+		Attributes:          attributes,
+		FederatedIdentities: *federatedIdentities,
+	}
+}
+
+func getUserFederatedIdentitiesFromData(data []interface{}) *keycloak.FederatedIdentities {
+	var federatedIdentities keycloak.FederatedIdentities
+	for _, d := range data {
+		federatedIdentitiesData := d.(map[string]interface{})
+		federatedIdentity := keycloak.FederatedIdentity{
+			IdentityProvider: federatedIdentitiesData["display_name"].(string),
+			UserId:           federatedIdentitiesData["name"].(string),
+			UserName:         federatedIdentitiesData["icon_uri"].(string),
+		}
+		federatedIdentities = append(federatedIdentities, federatedIdentity)
 	}
+	return &federatedIdentities
 }
 
 func mapFromUserToData(data *schema.ResourceData, user *keycloak.User) {


Test patch:
diff --git a/provider/data_source_keycloak_openid_client_authorization_policy_test.go b/provider/data_source_keycloak_openid_client_authorization_policy_test.go
new file mode 100644
index 0000000..8016a98
--- /dev/null
+++ b/provider/data_source_keycloak_openid_client_authorization_policy_test.go
@@ -0,0 +1,68 @@
+package provider
+
+import (
+	"fmt"
+	"github.com/hashicorp/terraform/helper/acctest"
+	"github.com/hashicorp/terraform/helper/resource"
+	"regexp"
+	"testing"
+)
+
+func TestAccKeycloakDataSourceOpenidClientAuthorizationPolicy_basic(t *testing.T) {
+	realm := acctest.RandomWithPrefix("tf-acc-test")
+	clientId := acctest.RandomWithPrefix("tf-acc-test")
+	dataSourceName := "data.keycloak_openid_client_authorization_policy.test"
+
+	resource.ParallelTest(t, resource.TestCase{
+		PreCheck:  func() { testAccPreCheck(t) },
+		Providers: testAccProviders,
+		Steps: []resource.TestStep{
+			{
+				Config: testAccKeycloakOpenidClientAuthorizationPolicyConfig(realm, clientId),
+				Check: resource.ComposeTestCheckFunc(
+					resource.TestMatchResourceAttr(dataSourceName, "resource_server_id", regexp.MustCompile("^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-4[a-fA-F0-9]{3}-[8|9|aA|bB][a-fA-F0-9]{3}-[a-fA-F0-9]{12}$")),
+					resource.TestCheckResourceAttr(dataSourceName, "realm_id", realm),
+					resource.TestCheckResourceAttr(dataSourceName, "name", "default"),
+					resource.TestCheckResourceAttr(dataSourceName, "decision_strategy", "UNANIMOUS"),
+					resource.TestCheckResourceAttr(dataSourceName, "logic", "POSITIVE"),
+					resource.TestCheckResourceAttr(dataSourceName, "type", "resource"),
+				),
+			},
+		},
+	})
+}
+
+func testAccKeycloakOpenidClientAuthorizationPolicyConfig(realm, clientId string) string {
+	return fmt.Sprintf(`
+resource keycloak_realm test {
+  realm                = "%s"
+  enabled              = true
+  display_name         = "foo"
+  account_theme        = "base"
+  access_code_lifespan = "30m"
+}
+
+resource keycloak_openid_client test {
+  client_id                      = "%s"
+  name                           = "%s"
+  realm_id                       = "${keycloak_realm.test.id}"
+  description                    = "a test openid client"
+  standard_flow_enabled          = true
+  service_accounts_enabled       = true
+  access_type                    = "CONFIDENTIAL"
+  client_secret                  = "secret"
+  valid_redirect_uris            = [
+    "http://localhost:5555/callback",
+  ]
+  authorization {
+  	 policy_enforcement_mode = "ENFORCING"
+  }
+}
+
+data keycloak_openid_client_authorization_policy test {
+	resource_server_id = "${keycloak_openid_client.test.resource_server_id}"
+	realm_id           = "${keycloak_realm.test.id}"
+	name               = "default"
+}
+`, realm, clientId, clientId)
+}
diff --git a/provider/data_source_keycloak_openid_client_test.go b/provider/data_source_keycloak_openid_client_test.go
new file mode 100644
index 0000000..b8408e1
--- /dev/null
+++ b/provider/data_source_keycloak_openid_client_test.go
@@ -0,0 +1,76 @@
+package provider
+
+import (
+	"fmt"
+	"github.com/hashicorp/terraform/helper/acctest"
+	"github.com/hashicorp/terraform/helper/resource"
+	"testing"
+)
+
+func TestAccKeycloakDataSourceOpenidClient_basic(t *testing.T) {
+	realm := acctest.RandomWithPrefix("tf-acc-test")
+	clientId := acctest.RandomWithPrefix("tf-acc-test")
+	dataSourceName := "data.keycloak_openid_client.test"
+	resourceName := "keycloak_openid_client.test"
+
+	resource.ParallelTest(t, resource.TestCase{
+		PreCheck:  func() { testAccPreCheck(t) },
+		Providers: testAccProviders,
+		Steps: []resource.TestStep{
+			{
+				Config: testAccKeycloakOpenidClientConfig(realm, clientId),
+				Check: resource.ComposeAggregateTestCheckFunc(
+					resource.TestCheckResourceAttrPair(dataSourceName, "client_id", resourceName, "client_id"),
+					resource.TestCheckResourceAttrPair(dataSourceName, "realm_id", resourceName, "realm_id"),
+					resource.TestCheckResourceAttrPair(dataSourceName, "name", resourceName, "name"),
+					resource.TestCheckResourceAttrPair(dataSourceName, "enabled", resourceName, "enabled"),
+					resource.TestCheckResourceAttrPair(dataSourceName, "description", resourceName, "description"),
+					resource.TestCheckResourceAttrPair(dataSourceName, "access_type", resourceName, "access_type"),
+					resource.TestCheckResourceAttrPair(dataSourceName, "standard_flow_enabled", resourceName, "standard_flow_enabled"),
+					resource.TestCheckResourceAttrPair(dataSourceName, "implicit_flow_enabled", resourceName, "implicit_flow_enabled"),
+					resource.TestCheckResourceAttrPair(dataSourceName, "direct_access_grants_enabled", resourceName, "direct_access_grants_enabled"),
+					resource.TestCheckResourceAttrPair(dataSourceName, "service_account_user_id", resourceName, "service_account_user_id"),
+					resource.TestCheckResourceAttrPair(dataSourceName, "service_accounts_enabled", resourceName, "service_accounts_enabled"),
+					resource.TestCheckResourceAttrPair(dataSourceName, "resource_server_id", resourceName, "resource_server_id"),
+				),
+			},
+		},
+	})
+}
+
+func testAccKeycloakOpenidClientConfig(realm, clientId string) string {
+	return fmt.Sprintf(`
+resource keycloak_realm test {
+  realm                = "%s"
+  enabled              = true
+  display_name         = "foo"
+  account_theme        = "base"
+  access_code_lifespan = "30m"
+}
+
+resource keycloak_openid_client test {
+  name                  	= "%s"
+  client_id 					= "%s"
+  realm_id              	= "${keycloak_realm.test.id}"
+  description           	= "a test openid client"
+  standard_flow_enabled    = true
+  access_type              = "CONFIDENTIAL"
+  service_accounts_enabled = true
+  client_secret            = "secret"
+  valid_redirect_uris      = [
+   	"http://localhost:5555/callback",
+  ]
+  authorization {
+  		policy_enforcement_mode = "ENFORCING"
+  }
+  web_origins              = [
+		"http://localhost"
+  ]
+}
+
+data keycloak_openid_client test {
+  client_id = "${keycloak_openid_client.test.client_id}"
+  realm_id  = "${keycloak_realm.test.id}"
+}
+`, realm, clientId, clientId)
+}
diff --git a/provider/resource_keycloak_openid_client_authorization_permission_test.go b/provider/resource_keycloak_openid_client_authorization_permission_test.go
new file mode 100644
index 0000000..eaf373b
--- /dev/null
+++ b/provider/resource_keycloak_openid_client_authorization_permission_test.go
@@ -0,0 +1,279 @@
+package provider
+
+import (
+	"fmt"
+	"github.com/hashicorp/terraform/helper/acctest"
+	"github.com/hashicorp/terraform/helper/resource"
+	"github.com/hashicorp/terraform/terraform"
+	"github.com/mrparkers/terraform-provider-keycloak/keycloak"
+	"testing"
+)
+
+func TestAccKeycloakOpenidClientAuthorizationPermission_basic(t *testing.T) {
+	realmName := "terraform-" + acctest.RandString(10)
+	clientId := "terraform-" + acctest.RandString(10)
+	resourceName := "terraform-" + acctest.RandString(10)
+	permissionName := "terraform-" + acctest.RandString(10)
+
+	resource.Test(t, resource.TestCase{
+		Providers:    testAccProviders,
+		PreCheck:     func() { testAccPreCheck(t) },
+		CheckDestroy: testAccCheckKeycloakOpenidClientAuthorizationPermissionDestroy(),
+		Steps: []resource.TestStep{
+			{
+				Config: testKeycloakOpenidClientAuthorizationPermission_basic(realmName, clientId, resourceName, permissionName),
+				Check:  testAccCheckKeycloakOpenidClientAuthorizationPermissionExists("keycloak_openid_client_authorization_permission.test"),
+			},
+		},
+	})
+}
+
+func TestAccKeycloakOpenidClientAuthorizationPermission_createAfterManualDestroy(t *testing.T) {
+	var authorizationPermission = &keycloak.OpenidClientAuthorizationPermission{}
+
+	realmName := "terraform-" + acctest.RandString(10)
+	clientId := "terraform-" + acctest.RandString(10)
+	resourceName := "terraform-" + acctest.RandString(10)
+	permissionName := "terraform-" + acctest.RandString(10)
+
+	resource.Test(t, resource.TestCase{
+		Providers:    testAccProviders,
+		PreCheck:     func() { testAccPreCheck(t) },
+		CheckDestroy: testAccCheckKeycloakOpenidClientAuthorizationPermissionDestroy(),
+		Steps: []resource.TestStep{
+			{
+				Config: testKeycloakOpenidClientAuthorizationPermission_basic(realmName, clientId, resourceName, permissionName),
+				Check:  testAccCheckKeycloakOpenidClientAuthorizationPermissionFetch("keycloak_openid_client_authorization_permission.test", authorizationPermission),
+			},
+			{
+				PreConfig: func() {
+					keycloakClient := testAccProvider.Meta().(*keycloak.KeycloakClient)
+
+					err := keycloakClient.DeleteOpenidClientAuthorizationPermission(authorizationPermission.RealmId, authorizationPermission.ResourceServerId, authorizationPermission.Id)
+					if err != nil {
+						t.Fatal(err)
+					}
+				},
+				Config: testKeycloakOpenidClientAuthorizationPermission_basic(realmName, clientId, resourceName, permissionName),
+				Check:  testAccCheckKeycloakOpenidClientAuthorizationPermissionExists("keycloak_openid_client_authorization_permission.test"),
+			},
+		},
+	})
+}
+
+func TestAccKeycloakOpenidClientAuthorizationPermission_basicUpdateRealm(t *testing.T) {
+	firstRealm := "terraform-" + acctest.RandString(10)
+	secondRealm := "terraform-" + acctest.RandString(10)
+	clientId := "terraform-" + acctest.RandString(10)
+	resourceName := "terraform-" + acctest.RandString(10)
+	permissionName := "terraform-" + acctest.RandString(10)
+
+	resource.Test(t, resource.TestCase{
+		Providers:    testAccProviders,
+		PreCheck:     func() { testAccPreCheck(t) },
+		CheckDestroy: testAccCheckKeycloakOpenidClientAuthorizationPermissionDestroy(),
+		Steps: []resource.TestStep{
+			{
+				Config: testKeycloakOpenidClientAuthorizationPermission_basic(firstRealm, clientId, resourceName, permissionName),
+				Check: resource.ComposeTestCheckFunc(
+					testAccCheckKeycloakOpenidClientAuthorizationPermissionExists("keycloak_openid_client_authorization_permission.test"),
+					resource.TestCheckResourceAttr("keycloak_openid_client_authorization_permission.test", "realm_id", firstRealm),
+				),
+			},
+			{
+				Config: testKeycloakOpenidClientAuthorizationPermission_basic(secondRealm, clientId, resourceName, permissionName),
+				Check: resource.ComposeTestCheckFunc(
+					testAccCheckKeycloakOpenidClientAuthorizationPermissionExists("keycloak_openid_client_authorization_permission.test"),
+					resource.TestCheckResourceAttr("keycloak_openid_client_authorization_permission.test", "realm_id", secondRealm),
+				),
+			},
+		},
+	})
+}
+
+func TestAccKeycloakOpenidClientAuthorizationPermission_basicUpdateAll(t *testing.T) {
+	realmName := "terraform-" + acctest.RandString(10)
+	clientId := "terraform-" + acctest.RandString(10)
+
+	firstAuthrorizationPermission := &keycloak.OpenidClientAuthorizationPermission{
+		RealmId:     realmName,
+		Name:        acctest.RandString(10),
+		Description: acctest.RandString(10),
+	}
+
+	secondAuthrorizationPermission := &keycloak.OpenidClientAuthorizationPermission{
+		RealmId:     realmName,
+		Name:        acctest.RandString(10),
+		Description: acctest.RandString(10),
+	}
+
+	resource.Test(t, resource.TestCase{
+		Providers:    testAccProviders,
+		PreCheck:     func() { testAccPreCheck(t) },
+		CheckDestroy: testAccCheckKeycloakOpenidClientAuthorizationPermissionDestroy(),
+		Steps: []resource.TestStep{
+			{
+				Config: testKeycloakOpenidClientAuthorizationPermission_basicFromInterface(clientId, firstAuthrorizationPermission, acctest.RandString(10)),
+				Check:  testAccCheckKeycloakOpenidClientAuthorizationPermissionExists("keycloak_openid_client_authorization_permission.test"),
+			},
+			{
+				Config: testKeycloakOpenidClientAuthorizationPermission_basicFromInterface(clientId, secondAuthrorizationPermission, acctest.RandString(10)),
+				Check:  testAccCheckKeycloakOpenidClientAuthorizationPermissionExists("keycloak_openid_client_authorization_permission.test"),
+			},
+		},
+	})
+}
+
+func testAccCheckKeycloakOpenidClientAuthorizationPermissionExists(resourceName string) resource.TestCheckFunc {
+	return func(s *terraform.State) error {
+		_, err := getKeycloakOpenidClientAuthorizationPermissionFromState(s, resourceName)
+		if err != nil {
+			return err
+		}
+
+		return nil
+	}
+}
+
+func testAccCheckKeycloakOpenidClientAuthorizationPermissionFetch(resourceName string, mapper *keycloak.OpenidClientAuthorizationPermission) resource.TestCheckFunc {
+	return func(s *terraform.State) error {
+		fetchedMapper, err := getKeycloakOpenidClientAuthorizationPermissionFromState(s, resourceName)
+		if err != nil {
+			return err
+		}
+
+		mapper.ResourceServerId = fetchedMapper.ResourceServerId
+		mapper.RealmId = fetchedMapper.RealmId
+		mapper.Id = fetchedMapper.Id
+
+		return nil
+	}
+}
+
+func testAccCheckKeycloakOpenidClientAuthorizationPermissionDestroy() resource.TestCheckFunc {
+	return func(s *terraform.State) error {
+		for _, rs := range s.RootModule().Resources {
+			if rs.Type != "keycloak_openid_client_authorization_permission" {
+				continue
+			}
+
+			realmId := rs.Primary.Attributes["realm_id"]
+			resourceServerId := rs.Primary.Attributes["resource_server_id"]
+			id := rs.Primary.ID
+
+			keycloakClient := testAccProvider.Meta().(*keycloak.KeycloakClient)
+
+			authorizationPermission, _ := keycloakClient.GetOpenidClientAuthorizationPermission(realmId, resourceServerId, id)
+			if authorizationPermission != nil {
+				return fmt.Errorf("test config with id %s still exists", id)
+			}
+		}
+
+		return nil
+	}
+}
+
+func getKeycloakOpenidClientAuthorizationPermissionFromState(s *terraform.State, resourceName string) (*keycloak.OpenidClientAuthorizationPermission, error) {
+	keycloakClient := testAccProvider.Meta().(*keycloak.KeycloakClient)
+
+	rs, ok := s.RootModule().Resources[resourceName]
+	if !ok {
+		return nil, fmt.Errorf("resource not found: %s", resourceName)
+	}
+
+	realmId := rs.Primary.Attributes["realm_id"]
+	resourceServerId := rs.Primary.Attributes["resource_server_id"]
+	id := rs.Primary.ID
+
+	authorizationPermission, err := keycloakClient.GetOpenidClientAuthorizationPermission(realmId, resourceServerId, id)
+	if err != nil {
+		return nil, fmt.Errorf("error getting authorization permission config with id %s: %s", id, err)
+	}
+
+	return authorizationPermission, nil
+}
+
+func testKeycloakOpenidClientAuthorizationPermission_basic(realm, clientId, resourceName, permissionName string) string {
+	return fmt.Sprintf(`
+resource keycloak_realm test {
+	realm = "%s"
+}
+
+resource keycloak_openid_client test {
+	client_id                = "%s"
+	realm_id                 = "${keycloak_realm.test.id}"
+	access_type              = "CONFIDENTIAL"
+	service_accounts_enabled = true
+	authorization {
+		policy_enforcement_mode = "ENFORCING"
+	}
+}
+
+data keycloak_openid_client_authorization_policy default {
+  realm_id           = "${keycloak_realm.test.id}"
+  resource_server_id = "${keycloak_openid_client.test.resource_server_id}"
+  name               = "default"
+}
+
+resource keycloak_openid_client_authorization_resource test {
+  resource_server_id = "${keycloak_openid_client.test.resource_server_id}"
+  name               = "%s"
+  realm_id           = "${keycloak_realm.test.id}"
+
+  uris = [
+    "/endpoint/*"
+  ]
+}
+
+resource keycloak_openid_client_authorization_permission test {
+	resource_server_id = "${keycloak_openid_client.test.resource_server_id}"
+	realm_id           = "${keycloak_realm.test.id}"
+	name               = "%s"
+	policies           = ["${data.keycloak_openid_client_authorization_policy.default.id}"]
+   resources          = ["${keycloak_openid_client_authorization_resource.test.id}"]
+}
+	`, realm, clientId, resourceName, permissionName)
+}
+
+func testKeycloakOpenidClientAuthorizationPermission_basicFromInterface(clientId string, authorizationPermission *keycloak.OpenidClientAuthorizationPermission, resourceName string) string {
+	return fmt.Sprintf(`
+resource keycloak_realm test {
+	realm = "%s"
+}
+
+resource keycloak_openid_client test {
+	client_id                = "%s"
+	realm_id                 = "${keycloak_realm.test.id}"
+	access_type              = "CONFIDENTIAL"
+	service_accounts_enabled = true
+	authorization {
+		policy_enforcement_mode = "ENFORCING"
+	}
+}
+
+data keycloak_openid_client_authorization_policy default {
+  realm_id           = "${keycloak_realm.test.id}"
+  resource_server_id = "${keycloak_openid_client.test.resource_server_id}"
+  name               = "default"
+}
+
+resource keycloak_openid_client_authorization_resource resource {
+  resource_server_id = "${keycloak_openid_client.test.resource_server_id}"
+  name               = "%s"
+  realm_id           = "${keycloak_realm.test.id}"
+
+  uris = [
+    "/endpoint/*"
+  ]
+}
+
+resource keycloak_openid_client_authorization_permission test {
+	resource_server_id = "${keycloak_openid_client.test.resource_server_id}"
+	realm_id           = "${keycloak_realm.test.id}"
+	name               = "%s"
+	policies           = ["${data.keycloak_openid_client_authorization_policy.default.id}"]
+   resources          = ["${keycloak_openid_client_authorization_resource.resource.id}"]
+   description        = "%s"
+}
+	`, authorizationPermission.RealmId, clientId, resourceName, authorizationPermission.Name, authorizationPermission.Description)
+}
diff --git a/provider/resource_keycloak_openid_client_authorization_resource_test.go b/provider/resource_keycloak_openid_client_authorization_resource_test.go
new file mode 100644
index 0000000..7757cb2
--- /dev/null
+++ b/provider/resource_keycloak_openid_client_authorization_resource_test.go
@@ -0,0 +1,257 @@
+package provider
+
+import (
+	"fmt"
+	"github.com/hashicorp/terraform/helper/acctest"
+	"github.com/hashicorp/terraform/helper/resource"
+	"github.com/hashicorp/terraform/terraform"
+	"github.com/mrparkers/terraform-provider-keycloak/keycloak"
+	"testing"
+)
+
+func TestAccKeycloakOpenidClientAuthorizationResource_basic(t *testing.T) {
+	realmName := "terraform-" + acctest.RandString(10)
+	clientId := "terraform-" + acctest.RandString(10)
+	resourceName := "terraform-" + acctest.RandString(10)
+
+	resource.Test(t, resource.TestCase{
+		Providers:    testAccProviders,
+		PreCheck:     func() { testAccPreCheck(t) },
+		CheckDestroy: testAccCheckKeycloakOpenidClientAuthorizationResourceDestroy(),
+		Steps: []resource.TestStep{
+			{
+				Config: testKeycloakOpenidClientAuthorizationResource_basic(realmName, clientId, resourceName),
+				Check:  testAccCheckKeycloakOpenidClientAuthorizationResourceExists("keycloak_openid_client_authorization_resource.test"),
+			},
+		},
+	})
+}
+
+func TestAccKeycloakOpenidClientAuthorizationResource_createAfterManualDestroy(t *testing.T) {
+	var authorizationResource = &keycloak.OpenidClientAuthorizationResource{}
+
+	realmName := "terraform-" + acctest.RandString(10)
+	clientId := "terraform-" + acctest.RandString(10)
+	resourceName := "terraform-" + acctest.RandString(10)
+
+	resource.Test(t, resource.TestCase{
+		Providers:    testAccProviders,
+		PreCheck:     func() { testAccPreCheck(t) },
+		CheckDestroy: testAccCheckKeycloakOpenidClientAuthorizationResourceDestroy(),
+		Steps: []resource.TestStep{
+			{
+				Config: testKeycloakOpenidClientAuthorizationResource_basic(realmName, clientId, resourceName),
+				Check:  testAccCheckKeycloakOpenidClientAuthorizationResourceFetch("keycloak_openid_client_authorization_resource.test", authorizationResource),
+			},
+			{
+				PreConfig: func() {
+					keycloakClient := testAccProvider.Meta().(*keycloak.KeycloakClient)
+
+					err := keycloakClient.DeleteOpenidClientAuthorizationResource(authorizationResource.RealmId, authorizationResource.ResourceServerId, authorizationResource.Id)
+					if err != nil {
+						t.Fatal(err)
+					}
+				},
+				Config: testKeycloakOpenidClientAuthorizationResource_basic(realmName, clientId, resourceName),
+				Check:  testAccCheckKeycloakOpenidClientAuthorizationResourceExists("keycloak_openid_client_authorization_resource.test"),
+			},
+		},
+	})
+}
+
+func TestAccKeycloakOpenidClientAuthorizationResource_basicUpdateRealm(t *testing.T) {
+	firstRealm := "terraform-" + acctest.RandString(10)
+	secondRealm := "terraform-" + acctest.RandString(10)
+	clientId := "terraform-" + acctest.RandString(10)
+	resourceName := "terraform-" + acctest.RandString(10)
+
+	resource.Test(t, resource.TestCase{
+		Providers:    testAccProviders,
+		PreCheck:     func() { testAccPreCheck(t) },
+		CheckDestroy: testAccCheckKeycloakOpenidClientAuthorizationResourceDestroy(),
+		Steps: []resource.TestStep{
+			{
+				Config: testKeycloakOpenidClientAuthorizationResource_basic(firstRealm, clientId, resourceName),
+				Check: resource.ComposeTestCheckFunc(
+					testAccCheckKeycloakOpenidClientAuthorizationResourceExists("keycloak_openid_client_authorization_resource.test"),
+					resource.TestCheckResourceAttr("keycloak_openid_client_authorization_resource.test", "realm_id", firstRealm),
+				),
+			},
+			{
+				Config: testKeycloakOpenidClientAuthorizationResource_basic(secondRealm, clientId, resourceName),
+				Check: resource.ComposeTestCheckFunc(
+					testAccCheckKeycloakOpenidClientAuthorizationResourceExists("keycloak_openid_client_authorization_resource.test"),
+					resource.TestCheckResourceAttr("keycloak_openid_client_authorization_resource.test", "realm_id", secondRealm),
+				),
+			},
+		},
+	})
+}
+
+func TestAccKeycloakOpenidClientAuthorizationResource_basicUpdateAll(t *testing.T) {
+	realmName := "terraform-" + acctest.RandString(10)
+	clientId := "terraform-" + acctest.RandString(10)
+	ownerManagedAccess := randomBool()
+
+	firstAuthrorizationResource := &keycloak.OpenidClientAuthorizationResource{
+		RealmId:            realmName,
+		Name:               acctest.RandString(10),
+		DisplayName:        acctest.RandString(10),
+		IconUri:            acctest.RandString(10),
+		Type:               acctest.RandString(10),
+		OwnerManagedAccess: ownerManagedAccess,
+	}
+
+	secondAuthrorizationResource := &keycloak.OpenidClientAuthorizationResource{
+		RealmId:            realmName,
+		Name:               acctest.RandString(10),
+		DisplayName:        acctest.RandString(10),
+		IconUri:            acctest.RandString(10),
+		Type:               acctest.RandString(10),
+		OwnerManagedAccess: !ownerManagedAccess,
+	}
+
+	resource.Test(t, resource.TestCase{
+		Providers:    testAccProviders,
+		PreCheck:     func() { testAccPreCheck(t) },
+		CheckDestroy: testAccCheckKeycloakOpenidClientAuthorizationResourceDestroy(),
+		Steps: []resource.TestStep{
+			{
+				Config: testKeycloakOpenidClientAuthorizationResource_basicFromInterface(clientId, firstAuthrorizationResource),
+				Check:  testAccCheckKeycloakOpenidClientAuthorizationResourceExists("keycloak_openid_client_authorization_resource.test"),
+			},
+			{
+				Config: testKeycloakOpenidClientAuthorizationResource_basicFromInterface(clientId, secondAuthrorizationResource),
+				Check:  testAccCheckKeycloakOpenidClientAuthorizationResourceExists("keycloak_openid_client_authorization_resource.test"),
+			},
+		},
+	})
+}
+
+func testAccCheckKeycloakOpenidClientAuthorizationResourceExists(resourceName string) resource.TestCheckFunc {
+	return func(s *terraform.State) error {
+		_, err := getKeycloakOpenidClientAuthorizationResourceFromState(s, resourceName)
+		if err != nil {
+			return err
+		}
+
+		return nil
+	}
+}
+
+func testAccCheckKeycloakOpenidClientAuthorizationResourceFetch(resourceName string, mapper *keycloak.OpenidClientAuthorizationResource) resource.TestCheckFunc {
+	return func(s *terraform.State) error {
+		fetchedMapper, err := getKeycloakOpenidClientAuthorizationResourceFromState(s, resourceName)
+		if err != nil {
+			return err
+		}
+
+		mapper.ResourceServerId = fetchedMapper.ResourceServerId
+		mapper.RealmId = fetchedMapper.RealmId
+		mapper.Id = fetchedMapper.Id
+
+		return nil
+	}
+}
+
+func testAccCheckKeycloakOpenidClientAuthorizationResourceDestroy() resource.TestCheckFunc {
+	return func(s *terraform.State) error {
+		for _, rs := range s.RootModule().Resources {
+			if rs.Type != "keycloak_openid_client_authorization_resource" {
+				continue
+			}
+
+			realmId := rs.Primary.Attributes["realm_id"]
+			resourceServerId := rs.Primary.Attributes["resource_server_id"]
+			id := rs.Primary.ID
+
+			keycloakClient := testAccProvider.Meta().(*keycloak.KeycloakClient)
+
+			authorizationResource, _ := keycloakClient.GetOpenidClientAuthorizationResource(realmId, resourceServerId, id)
+			if authorizationResource != nil {
+				return fmt.Errorf("test config with id %s still exists", id)
+			}
+		}
+
+		return nil
+	}
+}
+
+func getKeycloakOpenidClientAuthorizationResourceFromState(s *terraform.State, resourceName string) (*keycloak.OpenidClientAuthorizationResource, error) {
+	keycloakClient := testAccProvider.Meta().(*keycloak.KeycloakClient)
+
+	rs, ok := s.RootModule().Resources[resourceName]
+	if !ok {
+		return nil, fmt.Errorf("resource not found: %s", resourceName)
+	}
+
+	realmId := rs.Primary.Attributes["realm_id"]
+	resourceServerId := rs.Primary.Attributes["resource_server_id"]
+	id := rs.Primary.ID
+
+	authorizationResource, err := keycloakClient.GetOpenidClientAuthorizationResource(realmId, resourceServerId, id)
+	if err != nil {
+		return nil, fmt.Errorf("error getting authorization resource config with id %s: %s", id, err)
+	}
+
+	return authorizationResource, nil
+}
+
+func testKeycloakOpenidClientAuthorizationResource_basic(realm, clientId, resourceName string) string {
+	return fmt.Sprintf(`
+resource keycloak_realm test {
+	realm = "%s"
+}
+
+resource keycloak_openid_client test {
+	client_id                = "%s"
+	realm_id                 = "${keycloak_realm.test.id}"
+	access_type              = "CONFIDENTIAL"
+	service_accounts_enabled = true
+	authorization {
+		policy_enforcement_mode = "ENFORCING"
+	}
+}
+
+resource keycloak_openid_client_authorization_resource test {
+  resource_server_id = "${keycloak_openid_client.test.resource_server_id}"
+  name               = "%s"
+  realm_id           = "${keycloak_realm.test.id}"
+
+  uris = [
+    "/endpoint/*"
+  ]
+}
+	`, realm, clientId, resourceName)
+}
+
+func testKeycloakOpenidClientAuthorizationResource_basicFromInterface(clientId string, authorizationResource *keycloak.OpenidClientAuthorizationResource) string {
+	return fmt.Sprintf(`
+resource keycloak_realm test {
+	realm = "%s"
+}
+
+resource keycloak_openid_client test {
+	client_id                = "%s"
+	realm_id                 = "${keycloak_realm.test.id}"
+	access_type              = "CONFIDENTIAL"
+	service_accounts_enabled = true
+	authorization {
+		policy_enforcement_mode = "ENFORCING"
+	}
+}
+
+resource keycloak_openid_client_authorization_resource test {
+  resource_server_id = "${keycloak_openid_client.test.resource_server_id}"
+  name                 = "%s"
+  realm_id             = "${keycloak_realm.test.id}"
+  display_name         = "%s"
+  icon_uri             = "%s"
+  owner_managed_access = %t
+  type                 = "%s"
+  uris = [
+    "/test/"
+  ]
+}
+	`, authorizationResource.RealmId, clientId, authorizationResource.Name, authorizationResource.DisplayName, authorizationResource.IconUri, authorizationResource.OwnerManagedAccess, authorizationResource.Type)
+}
diff --git a/provider/resource_keycloak_openid_client_authorization_scope_test.go b/provider/resource_keycloak_openid_client_authorization_scope_test.go
new file mode 100644
index 0000000..854322f
--- /dev/null
+++ b/provider/resource_keycloak_openid_client_authorization_scope_test.go
@@ -0,0 +1,243 @@
+package provider
+
+import (
+	"fmt"
+	"github.com/hashicorp/terraform/helper/acctest"
+	"github.com/hashicorp/terraform/helper/resource"
+	"github.com/hashicorp/terraform/terraform"
+	"github.com/mrparkers/terraform-provider-keycloak/keycloak"
+	"testing"
+)
+
+func TestAccKeycloakOpenidClientAuthorizationScope_basic(t *testing.T) {
+	realmName := "terraform-" + acctest.RandString(10)
+	clientId := "terraform-" + acctest.RandString(10)
+	scopeName := "terraform-" + acctest.RandString(10)
+
+	resource.Test(t, resource.TestCase{
+		Providers:    testAccProviders,
+		PreCheck:     func() { testAccPreCheck(t) },
+		CheckDestroy: testAccCheckKeycloakOpenidClientAuthorizationScopeDestroy(),
+		Steps: []resource.TestStep{
+			{
+				Config: testKeycloakOpenidClientAuthorizationScope_basic(realmName, clientId, scopeName),
+				Check:  testAccCheckKeycloakOpenidClientAuthorizationScopeExists("keycloak_openid_client_authorization_scope.test"),
+			},
+		},
+	})
+}
+
+func TestAccKeycloakOpenidClientAuthorizationScope_createAfterManualDestroy(t *testing.T) {
+	var authorizationScope = &keycloak.OpenidClientAuthorizationScope{}
+
+	realmName := "terraform-" + acctest.RandString(10)
+	clientId := "terraform-" + acctest.RandString(10)
+	scopeName := "terraform-" + acctest.RandString(10)
+
+	resource.Test(t, resource.TestCase{
+		Providers:    testAccProviders,
+		PreCheck:     func() { testAccPreCheck(t) },
+		CheckDestroy: testAccCheckKeycloakOpenidClientAuthorizationScopeDestroy(),
+		Steps: []resource.TestStep{
+			{
+				Config: testKeycloakOpenidClientAuthorizationScope_basic(realmName, clientId, scopeName),
+				Check:  testAccCheckKeycloakOpenidClientAuthorizationScopeFetch("keycloak_openid_client_authorization_scope.test", authorizationScope),
+			},
+			{
+				PreConfig: func() {
+					keycloakClient := testAccProvider.Meta().(*keycloak.KeycloakClient)
+
+					err := keycloakClient.DeleteOpenidClientAuthorizationScope(authorizationScope.RealmId, authorizationScope.ResourceServerId, authorizationScope.Id)
+					if err != nil {
+						t.Fatal(err)
+					}
+				},
+				Config: testKeycloakOpenidClientAuthorizationScope_basic(realmName, clientId, scopeName),
+				Check:  testAccCheckKeycloakOpenidClientAuthorizationScopeExists("keycloak_openid_client_authorization_scope.test"),
+			},
+		},
+	})
+}
+
+func TestAccKeycloakOpenidClientAuthorizationScope_basicUpdateRealm(t *testing.T) {
+	firstRealm := "terraform-" + acctest.RandString(10)
+	secondRealm := "terraform-" + acctest.RandString(10)
+	clientId := "terraform-" + acctest.RandString(10)
+	scopeName := "terraform-" + acctest.RandString(10)
+
+	resource.Test(t, resource.TestCase{
+		Providers:    testAccProviders,
+		PreCheck:     func() { testAccPreCheck(t) },
+		CheckDestroy: testAccCheckKeycloakOpenidClientAuthorizationScopeDestroy(),
+		Steps: []resource.TestStep{
+			{
+				Config: testKeycloakOpenidClientAuthorizationScope_basic(firstRealm, clientId, scopeName),
+				Check: resource.ComposeTestCheckFunc(
+					testAccCheckKeycloakOpenidClientAuthorizationScopeExists("keycloak_openid_client_authorization_scope.test"),
+					resource.TestCheckResourceAttr("keycloak_openid_client_authorization_scope.test", "realm_id", firstRealm),
+				),
+			},
+			{
+				Config: testKeycloakOpenidClientAuthorizationScope_basic(secondRealm, clientId, scopeName),
+				Check: resource.ComposeTestCheckFunc(
+					testAccCheckKeycloakOpenidClientAuthorizationScopeExists("keycloak_openid_client_authorization_scope.test"),
+					resource.TestCheckResourceAttr("keycloak_openid_client_authorization_scope.test", "realm_id", secondRealm),
+				),
+			},
+		},
+	})
+}
+
+func TestAccKeycloakOpenidClientAuthorizationScope_basicUpdateAll(t *testing.T) {
+	realmName := "terraform-" + acctest.RandString(10)
+	clientId := "terraform-" + acctest.RandString(10)
+
+	firstAuthrorizationScope := &keycloak.OpenidClientAuthorizationScope{
+		RealmId:     realmName,
+		Name:        acctest.RandString(10),
+		DisplayName: acctest.RandString(10),
+		IconUri:     acctest.RandString(10),
+	}
+
+	secondAuthrorizationScope := &keycloak.OpenidClientAuthorizationScope{
+		RealmId:     realmName,
+		Name:        acctest.RandString(10),
+		DisplayName: acctest.RandString(10),
+		IconUri:     acctest.RandString(10),
+	}
+
+	resource.Test(t, resource.TestCase{
+		Providers:    testAccProviders,
+		PreCheck:     func() { testAccPreCheck(t) },
+		CheckDestroy: testAccCheckKeycloakOpenidClientAuthorizationScopeDestroy(),
+		Steps: []resource.TestStep{
+			{
+				Config: testKeycloakOpenidClientAuthorizationScope_basicFromInterface(clientId, firstAuthrorizationScope),
+				Check:  testAccCheckKeycloakOpenidClientAuthorizationScopeExists("keycloak_openid_client_authorization_scope.test"),
+			},
+			{
+				Config: testKeycloakOpenidClientAuthorizationScope_basicFromInterface(clientId, secondAuthrorizationScope),
+				Check:  testAccCheckKeycloakOpenidClientAuthorizationScopeExists("keycloak_openid_client_authorization_scope.test"),
+			},
+		},
+	})
+}
+
+func testAccCheckKeycloakOpenidClientAuthorizationScopeExists(scopeName string) resource.TestCheckFunc {
+	return func(s *terraform.State) error {
+		_, err := getKeycloakOpenidClientAuthorizationScopeFromState(s, scopeName)
+		if err != nil {
+			return err
+		}
+
+		return nil
+	}
+}
+
+func testAccCheckKeycloakOpenidClientAuthorizationScopeFetch(scopeName string, authorizationScope *keycloak.OpenidClientAuthorizationScope) resource.TestCheckFunc {
+	return func(s *terraform.State) error {
+		fetchedAuthorizationScope, err := getKeycloakOpenidClientAuthorizationScopeFromState(s, scopeName)
+		if err != nil {
+			return err
+		}
+
+		authorizationScope.ResourceServerId = fetchedAuthorizationScope.ResourceServerId
+		authorizationScope.RealmId = fetchedAuthorizationScope.RealmId
+		authorizationScope.Id = fetchedAuthorizationScope.Id
+
+		return nil
+	}
+}
+
+func testAccCheckKeycloakOpenidClientAuthorizationScopeDestroy() resource.TestCheckFunc {
+	return func(s *terraform.State) error {
+		for _, rs := range s.RootModule().Resources {
+			if rs.Type != "keycloak_openid_client_authorization_scope" {
+				continue
+			}
+
+			realmId := rs.Primary.Attributes["realm_id"]
+			resourceServerId := rs.Primary.Attributes["resource_server_id"]
+			id := rs.Primary.ID
+
+			keycloakClient := testAccProvider.Meta().(*keycloak.KeycloakClient)
+
+			authorizationScope, _ := keycloakClient.GetOpenidClientAuthorizationScope(realmId, resourceServerId, id)
+			if authorizationScope != nil {
+				return fmt.Errorf("test config with id %s still exists", id)
+			}
+		}
+
+		return nil
+	}
+}
+
+func getKeycloakOpenidClientAuthorizationScopeFromState(s *terraform.State, scopeName string) (*keycloak.OpenidClientAuthorizationScope, error) {
+	keycloakClient := testAccProvider.Meta().(*keycloak.KeycloakClient)
+
+	rs, ok := s.RootModule().Resources[scopeName]
+	if !ok {
+		return nil, fmt.Errorf("resource not found: %s", scopeName)
+	}
+
+	realmId := rs.Primary.Attributes["realm_id"]
+	resourceServerId := rs.Primary.Attributes["resource_server_id"]
+	id := rs.Primary.ID
+
+	authorizationScope, err := keycloakClient.GetOpenidClientAuthorizationScope(realmId, resourceServerId, id)
+	if err != nil {
+		return nil, fmt.Errorf("error getting authorization scope config with id %s: %s", id, err)
+	}
+
+	return authorizationScope, nil
+}
+
+func testKeycloakOpenidClientAuthorizationScope_basic(realm, clientId, scopeName string) string {
+	return fmt.Sprintf(`
+resource keycloak_realm test {
+	realm = "%s"
+}
+
+resource keycloak_openid_client test {
+	client_id                = "%s"
+	realm_id                 = "${keycloak_realm.test.id}"
+	access_type              = "CONFIDENTIAL"
+	service_accounts_enabled = true
+	authorization {
+		policy_enforcement_mode = "ENFORCING"
+	}
+}
+
+resource keycloak_openid_client_authorization_scope test {
+  resource_server_id = "${keycloak_openid_client.test.resource_server_id}"
+  name               = "%s"
+  realm_id           = "${keycloak_realm.test.id}"
+}
+	`, realm, clientId, scopeName)
+}
+
+func testKeycloakOpenidClientAuthorizationScope_basicFromInterface(clientId string, authorizationScope *keycloak.OpenidClientAuthorizationScope) string {
+	return fmt.Sprintf(`
+resource keycloak_realm test {
+	realm = "%s"
+}
+
+resource keycloak_openid_client test {
+	client_id                = "%s"
+	realm_id                 = "${keycloak_realm.test.id}"
+	access_type              = "CONFIDENTIAL"
+	service_accounts_enabled = true
+	authorization {
+		policy_enforcement_mode = "ENFORCING"
+	}
+}
+
+resource keycloak_openid_client_authorization_scope test {
+  resource_server_id = "${keycloak_openid_client.test.resource_server_id}"
+  name                 = "%s"
+  realm_id             = "${keycloak_realm.test.id}"
+  display_name         = "%s"
+  icon_uri             = "%s"
+}
+	`, authorizationScope.RealmId, clientId, authorizationScope.Name, authorizationScope.DisplayName, authorizationScope.IconUri)
+}
diff --git a/provider/resource_keycloak_openid_client_default_scopes_test.go b/provider/resource_keycloak_openid_client_default_scopes_test.go
index 3358743..9b1d63b 100644
--- a/provider/resource_keycloak_openid_client_default_scopes_test.go
+++ b/provider/resource_keycloak_openid_client_default_scopes_test.go
@@ -407,8 +407,6 @@ resource "keycloak_openid_client" "client" {
 	client_id   = "%s"
 	realm_id    = "${keycloak_realm.realm.id}"
 	access_type = "PUBLIC"
-
-	valid_redirect_uris = ["foo"]
 }
 
 resource "keycloak_openid_client_scope" "client_scope" {
@@ -442,8 +440,6 @@ resource "keycloak_openid_client" "client" {
 	client_id   = "%s"
 	realm_id    = "${keycloak_realm.realm.id}"
 	access_type = "PUBLIC"
-
-	valid_redirect_uris = ["foo"]
 }
 
 resource "keycloak_openid_client_scope" "client_scope" {
@@ -465,8 +461,6 @@ resource "keycloak_openid_client" "client" {
 	client_id   = "%s"
 	realm_id    = "${keycloak_realm.realm.id}"
 	access_type = "PUBLIC"
-
-	valid_redirect_uris = ["foo"]
 }
 
 resource "keycloak_openid_client_scope" "client_scope" {
@@ -523,8 +517,6 @@ resource "keycloak_openid_client" "client" {
 	client_id   = "%s"
 	realm_id    = "${keycloak_realm.realm.id}"
 	access_type = "BEARER-ONLY"
-
-	valid_redirect_uris = ["foo"]
 }
 
 resource "keycloak_openid_client_scope" "client_scope" {
@@ -579,8 +571,6 @@ resource "keycloak_openid_client" "client" {
 	client_id   = "%s"
 	realm_id    = "${keycloak_realm.realm.id}"
 	access_type = "PUBLIC"
-
-	valid_redirect_uris = ["foo"]
 }
 
 %s
diff --git a/provider/resource_keycloak_openid_client_optional_scopes_test.go b/provider/resource_keycloak_openid_client_optional_scopes_test.go
index 994f781..910eca5 100644
--- a/provider/resource_keycloak_openid_client_optional_scopes_test.go
+++ b/provider/resource_keycloak_openid_client_optional_scopes_test.go
@@ -408,8 +408,6 @@ resource "keycloak_openid_client" "client" {
 	client_id   = "%s"
 	realm_id    = "${keycloak_realm.realm.id}"
 	access_type = "PUBLIC"
-
-	valid_redirect_uris = ["foo"]
 }
 
 resource "keycloak_openid_client_scope" "client_scope" {
@@ -443,8 +441,6 @@ resource "keycloak_openid_client" "client" {
 	client_id   = "%s"
 	realm_id    = "${keycloak_realm.realm.id}"
 	access_type = "PUBLIC"
-
-	valid_redirect_uris = ["foo"]
 }
 
 resource "keycloak_openid_client_scope" "client_scope" {
@@ -466,8 +462,6 @@ resource "keycloak_openid_client" "client" {
 	client_id   = "%s"
 	realm_id    = "${keycloak_realm.realm.id}"
 	access_type = "PUBLIC"
-
-	valid_redirect_uris = ["foo"]
 }
 
 resource "keycloak_openid_client_scope" "client_scope" {
@@ -524,8 +518,6 @@ resource "keycloak_openid_client" "client" {
 	client_id   = "%s"
 	realm_id    = "${keycloak_realm.realm.id}"
 	access_type = "BEARER-ONLY"
-
-	valid_redirect_uris = ["foo"]
 }
 
 resource "keycloak_openid_client_scope" "client_scope" {
@@ -580,8 +572,6 @@ resource "keycloak_openid_client" "client" {
 	client_id   = "%s"
 	realm_id    = "${keycloak_realm.realm.id}"
 	access_type = "PUBLIC"
-
-	valid_redirect_uris = ["foo"]
 }
 
 %s
diff --git a/provider/resource_keycloak_openid_client_service_account_role_test.go b/provider/resource_keycloak_openid_client_service_account_role_test.go
new file mode 100644
index 0000000..092e916
--- /dev/null
+++ b/provider/resource_keycloak_openid_client_service_account_role_test.go
@@ -0,0 +1,186 @@
+package provider
+
+import (
+	"fmt"
+	"github.com/hashicorp/terraform/helper/acctest"
+	"github.com/hashicorp/terraform/helper/resource"
+	"github.com/hashicorp/terraform/terraform"
+	"github.com/mrparkers/terraform-provider-keycloak/keycloak"
+	"testing"
+)
+
+func TestAccKeycloakOpenidClientServiceAccountRole_basic(t *testing.T) {
+	realmName := "terraform-" + acctest.RandString(10)
+	clientId := "terraform-" + acctest.RandString(10)
+
+	resource.Test(t, resource.TestCase{
+		Providers:    testAccProviders,
+		PreCheck:     func() { testAccPreCheck(t) },
+		CheckDestroy: testAccCheckKeycloakOpenidClientServiceAccountRoleDestroy(),
+		Steps: []resource.TestStep{
+			{
+				Config: testKeycloakOpenidClientServiceAccountRole_basic(realmName, clientId),
+				Check:  testAccCheckKeycloakOpenidClientServiceAccountRoleExists("keycloak_openid_client_service_account_role.test"),
+			},
+		},
+	})
+}
+
+func TestAccKeycloakOpenidClientServiceAccountRole_createAfterManualDestroy(t *testing.T) {
+	var serviceAccountRole = &keycloak.OpenidClientServiceAccountRole{}
+
+	realmName := "terraform-" + acctest.RandString(10)
+	clientId := "terraform-" + acctest.RandString(10)
+
+	resource.Test(t, resource.TestCase{
+		Providers:    testAccProviders,
+		PreCheck:     func() { testAccPreCheck(t) },
+		CheckDestroy: testAccCheckKeycloakOpenidClientServiceAccountRoleDestroy(),
+		Steps: []resource.TestStep{
+			{
+				Config: testKeycloakOpenidClientServiceAccountRole_basic(realmName, clientId),
+				Check:  testAccCheckKeycloakOpenidClientServiceAccountRoleFetch("keycloak_openid_client_service_account_role.test", serviceAccountRole),
+			},
+			{
+				PreConfig: func() {
+					keycloakClient := testAccProvider.Meta().(*keycloak.KeycloakClient)
+
+					err := keycloakClient.DeleteOpenidClientServiceAccountRole(serviceAccountRole.RealmId, serviceAccountRole.ServiceAccountUserId, serviceAccountRole.ContainerId, serviceAccountRole.Id)
+					if err != nil {
+						t.Fatal(err)
+					}
+				},
+				Config: testKeycloakOpenidClientServiceAccountRole_basic(realmName, clientId),
+				Check:  testAccCheckKeycloakOpenidClientServiceAccountRoleExists("keycloak_openid_client_service_account_role.test"),
+			},
+		},
+	})
+}
+
+func TestAccKeycloakOpenidClientServiceAccountRole_basicUpdateRealm(t *testing.T) {
+	firstRealm := "terraform-" + acctest.RandString(10)
+	secondRealm := "terraform-" + acctest.RandString(10)
+	clientId := "terraform-" + acctest.RandString(10)
+
+	resource.Test(t, resource.TestCase{
+		Providers:    testAccProviders,
+		PreCheck:     func() { testAccPreCheck(t) },
+		CheckDestroy: testAccCheckKeycloakOpenidClientServiceAccountRoleDestroy(),
+		Steps: []resource.TestStep{
+			{
+				Config: testKeycloakOpenidClientServiceAccountRole_basic(firstRealm, clientId),
+				Check: resource.ComposeTestCheckFunc(
+					testAccCheckKeycloakOpenidClientServiceAccountRoleExists("keycloak_openid_client_service_account_role.test"),
+					resource.TestCheckResourceAttr("keycloak_openid_client_service_account_role.test", "realm_id", firstRealm),
+				),
+			},
+			{
+				Config: testKeycloakOpenidClientServiceAccountRole_basic(secondRealm, clientId),
+				Check: resource.ComposeTestCheckFunc(
+					testAccCheckKeycloakOpenidClientServiceAccountRoleExists("keycloak_openid_client_service_account_role.test"),
+					resource.TestCheckResourceAttr("keycloak_openid_client_service_account_role.test", "realm_id", secondRealm),
+				),
+			},
+		},
+	})
+}
+
+func testAccCheckKeycloakOpenidClientServiceAccountRoleExists(resourceName string) resource.TestCheckFunc {
+	return func(s *terraform.State) error {
+		_, err := getKeycloakOpenidClientServiceAccountRoleFromState(s, resourceName)
+		if err != nil {
+			return err
+		}
+
+		return nil
+	}
+}
+
+func testAccCheckKeycloakOpenidClientServiceAccountRoleFetch(resourceName string, serviceAccountRole *keycloak.OpenidClientServiceAccountRole) resource.TestCheckFunc {
+	return func(s *terraform.State) error {
+		fetchedServiceAccountRole, err := getKeycloakOpenidClientServiceAccountRoleFromState(s, resourceName)
+		if err != nil {
+			return err
+		}
+
+		serviceAccountRole.ServiceAccountUserId = fetchedServiceAccountRole.ServiceAccountUserId
+		serviceAccountRole.RealmId = fetchedServiceAccountRole.RealmId
+		serviceAccountRole.ClientRole = fetchedServiceAccountRole.ClientRole
+		serviceAccountRole.ContainerId = fetchedServiceAccountRole.ContainerId
+		serviceAccountRole.Id = fetchedServiceAccountRole.Id
+
+		return nil
+	}
+}
+
+func testAccCheckKeycloakOpenidClientServiceAccountRoleDestroy() resource.TestCheckFunc {
+	return func(s *terraform.State) error {
+		for _, rs := range s.RootModule().Resources {
+			if rs.Type != "keycloak_openid_client_service_account_role" {
+				continue
+			}
+
+			realmId := rs.Primary.Attributes["realm_id"]
+			serviceAccountUserId := rs.Primary.Attributes["service_account_user_id"]
+			clientId := rs.Primary.Attributes["client_id"]
+			id := rs.Primary.ID
+
+			keycloakClient := testAccProvider.Meta().(*keycloak.KeycloakClient)
+
+			serviceAccountRole, _ := keycloakClient.GetOpenidClientServiceAccountRole(realmId, serviceAccountUserId, clientId, id)
+			if serviceAccountRole != nil {
+				return fmt.Errorf("service account role exists")
+			}
+		}
+
+		return nil
+	}
+}
+
+func getKeycloakOpenidClientServiceAccountRoleFromState(s *terraform.State, resourceName string) (*keycloak.OpenidClientServiceAccountRole, error) {
+	keycloakClient := testAccProvider.Meta().(*keycloak.KeycloakClient)
+
+	rs, ok := s.RootModule().Resources[resourceName]
+	if !ok {
+		return nil, fmt.Errorf("resource not found: %s", resourceName)
+	}
+
+	realmId := rs.Primary.Attributes["realm_id"]
+	serviceAccountUserId := rs.Primary.Attributes["service_account_user_id"]
+	clientId := rs.Primary.Attributes["client_id"]
+	id := rs.Primary.ID
+
+	serviceAccountRole, err := keycloakClient.GetOpenidClientServiceAccountRole(realmId, serviceAccountUserId, clientId, id)
+	if err != nil {
+		return nil, fmt.Errorf("error getting service account role mapping: %s", err)
+	}
+
+	return serviceAccountRole, nil
+}
+
+func testKeycloakOpenidClientServiceAccountRole_basic(realm, clientId string) string {
+	return fmt.Sprintf(`
+resource keycloak_realm test {
+	realm = "%s"
+}
+
+resource keycloak_openid_client test {
+	client_id                = "%s"
+	realm_id                 = "${keycloak_realm.test.id}"
+	access_type              = "CONFIDENTIAL"
+	service_accounts_enabled = true
+}
+
+data keycloak_openid_client broker {
+  realm_id  = "${keycloak_realm.test.id}"
+  client_id = "broker"
+}
+
+resource keycloak_openid_client_service_account_role test {
+	service_account_user_id = "${keycloak_openid_client.test.service_account_user_id}"
+	realm_id 					= "${keycloak_realm.test.id}"
+	client_id 					= "${data.keycloak_openid_client.broker.id}"
+	role 							= "read-token"
+}
+	`, realm, clientId)
+}
diff --git a/provider/resource_keycloak_openid_client_test.go b/provider/resource_keycloak_openid_client_test.go
index 889f56a..1beeb66 100644
--- a/provider/resource_keycloak_openid_client_test.go
+++ b/provider/resource_keycloak_openid_client_test.go
@@ -129,6 +129,10 @@ func TestAccKeycloakOpenidClient_updateInPlace(t *testing.T) {
 	directAccessGrantsEnabled := randomBool()
 	serviceAccountsEnabled := randomBool()
 
+	if !standardFlowEnabled {
+		implicitFlowEnabled = !standardFlowEnabled
+	}
+
 	openidClientBefore := &keycloak.OpenidClient{
 		RealmId:                   realm,
 		ClientId:                  clientId,
@@ -144,6 +148,8 @@ func TestAccKeycloakOpenidClient_updateInPlace(t *testing.T) {
 		WebOrigins:                []string{acctest.RandString(10), acctest.RandString(10), acctest.RandString(10)},
 	}
 
+	standardFlowEnabled, implicitFlowEnabled = implicitFlowEnabled, standardFlowEnabled
+
 	openidClientAfter := &keycloak.OpenidClient{
 		RealmId:                   realm,
 		ClientId:                  clientId,
@@ -151,8 +157,8 @@ func TestAccKeycloakOpenidClient_updateInPlace(t *testing.T) {
 		Enabled:                   !enabled,
 		Description:               acctest.RandString(50),
 		ClientSecret:              acctest.RandString(10),
-		StandardFlowEnabled:       !standardFlowEnabled,
-		ImplicitFlowEnabled:       !implicitFlowEnabled,
+		StandardFlowEnabled:       standardFlowEnabled,
+		ImplicitFlowEnabled:       implicitFlowEnabled,
 		DirectAccessGrantsEnabled: !directAccessGrantsEnabled,
 		ServiceAccountsEnabled:    !serviceAccountsEnabled,
 		ValidRedirectUris:         []string{acctest.RandString(10), acctest.RandString(10)},