dsl struct tags; wip
diff --git a/openstack/identity/v3/endpoints/errors.go b/openstack/identity/v3/endpoints/errors.go
deleted file mode 100644
index 854957f..0000000
--- a/openstack/identity/v3/endpoints/errors.go
+++ /dev/null
@@ -1,21 +0,0 @@
-package endpoints
-
-import "fmt"
-
-func requiredAttribute(attribute string) error {
-	return fmt.Errorf("You must specify %s for this endpoint.", attribute)
-}
-
-var (
-	// ErrAvailabilityRequired is reported if an Endpoint is created without an Availability.
-	ErrAvailabilityRequired = requiredAttribute("an availability")
-
-	// ErrNameRequired is reported if an Endpoint is created without a Name.
-	ErrNameRequired = requiredAttribute("a name")
-
-	// ErrURLRequired is reported if an Endpoint is created without a URL.
-	ErrURLRequired = requiredAttribute("a URL")
-
-	// ErrServiceIDRequired is reported if an Endpoint is created without a ServiceID.
-	ErrServiceIDRequired = requiredAttribute("a serviceID")
-)
diff --git a/openstack/identity/v3/endpoints/requests.go b/openstack/identity/v3/endpoints/requests.go
index c9b8cf5..7165fb4 100644
--- a/openstack/identity/v3/endpoints/requests.go
+++ b/openstack/identity/v3/endpoints/requests.go
@@ -5,59 +5,38 @@
 	"github.com/gophercloud/gophercloud/pagination"
 )
 
-// EndpointOpts contains the subset of Endpoint attributes that should be used to create or update an Endpoint.
-type EndpointOpts struct {
-	Availability gophercloud.Availability
-	Name         string
-	Region       string
-	URL          string
-	ServiceID    string
+type CreateOptsBuilder interface {
+	ToEndpointCreateMap() (map[string]interface{}, error)
+}
+
+// CreateOpts contains the subset of Endpoint attributes that should be used to create an Endpoint.
+type CreateOpts struct {
+	Availability gophercloud.Availability `json:"interface" required:"true"`
+	Name         string                   `json:"name" required:"true"`
+	Region       string                   `json:"region,omitempty"`
+	URL          string                   `json:"url" required:"true"`
+	ServiceID    string                   `json:"service_id" required:"true"`
+}
+
+func (opts CreateOpts) ToEndpointCreateMap() (map[string]interface{}, error) {
+	return gophercloud.BuildRequestBody(opts, "endpoint")
 }
 
 // Create inserts a new Endpoint into the service catalog.
 // Within EndpointOpts, Region may be omitted by being left as "", but all other fields are required.
-func Create(client *gophercloud.ServiceClient, opts EndpointOpts) CreateResult {
-	// Redefined so that Region can be re-typed as a *string, which can be omitted from the JSON output.
-	type endpoint struct {
-		Interface string  `json:"interface"`
-		Name      string  `json:"name"`
-		Region    *string `json:"region,omitempty"`
-		URL       string  `json:"url"`
-		ServiceID string  `json:"service_id"`
+func Create(client *gophercloud.ServiceClient, opts CreateOptsBuilder) CreateResult {
+	var r CreateResult
+	b, err := opts.ToEndpointCreateMap()
+	if err != nil {
+		r.Err = err
+		return r
 	}
+	_, r.Err = client.Post(listURL(client), &b, &r.Body, nil)
+	return r
+}
 
-	type request struct {
-		Endpoint endpoint `json:"endpoint"`
-	}
-
-	// Ensure that EndpointOpts is fully populated.
-	if opts.Availability == "" {
-		return createErr(ErrAvailabilityRequired)
-	}
-	if opts.Name == "" {
-		return createErr(ErrNameRequired)
-	}
-	if opts.URL == "" {
-		return createErr(ErrURLRequired)
-	}
-	if opts.ServiceID == "" {
-		return createErr(ErrServiceIDRequired)
-	}
-
-	// Populate the request body.
-	reqBody := request{
-		Endpoint: endpoint{
-			Interface: string(opts.Availability),
-			Name:      opts.Name,
-			URL:       opts.URL,
-			ServiceID: opts.ServiceID,
-		},
-	}
-	reqBody.Endpoint.Region = gophercloud.MaybeString(opts.Region)
-
-	var result CreateResult
-	_, result.Err = client.Post(listURL(client), reqBody, &result.Body, nil)
-	return result
+type ListOptsBuilder interface {
+	ToEndpointListParams() (string, error)
 }
 
 // ListOpts allows finer control over the endpoints returned by a List call.
@@ -69,55 +48,58 @@
 	PerPage      int                      `q:"per_page"`
 }
 
-// List enumerates endpoints in a paginated collection, optionally filtered by ListOpts criteria.
-func List(client *gophercloud.ServiceClient, opts ListOpts) pagination.Pager {
-	u := listURL(client)
+func (opts ListOpts) ToEndpointListParams() (string, error) {
 	q, err := gophercloud.BuildQueryString(opts)
-	if err != nil {
-		return pagination.Pager{Err: err}
-	}
-	u += q.String()
-	createPage := func(r pagination.PageResult) pagination.Page {
-		return EndpointPage{pagination.LinkedPageBase{PageResult: r}}
-	}
+	return q.String(), err
+}
 
-	return pagination.NewPager(client, u, createPage)
+// List enumerates endpoints in a paginated collection, optionally filtered by ListOpts criteria.
+func List(client *gophercloud.ServiceClient, opts ListOptsBuilder) pagination.Pager {
+	u := listURL(client)
+	if opts != nil {
+		q, err := gophercloud.BuildQueryString(opts)
+		if err != nil {
+			return pagination.Pager{Err: err}
+		}
+		u += q.String()
+	}
+	return pagination.NewPager(client, u, func(r pagination.PageResult) pagination.Page {
+		return EndpointPage{pagination.LinkedPageBase{PageResult: r}}
+	})
+}
+
+type UpdateOptsBuilder interface {
+	ToEndpointUpdateMap() (map[string]interface{}, error)
+}
+
+// UpdateOpts contains the subset of Endpoint attributes that should be used to update an Endpoint.
+type UpdateOpts struct {
+	Availability gophercloud.Availability `json:"interface,omitempty"`
+	Name         string                   `json:"name,omitempty"`
+	Region       string                   `json:"region,omitempty"`
+	URL          string                   `json:"url,omitempty"`
+	ServiceID    string                   `json:"service_id,omitempty"`
+}
+
+func (opts UpdateOpts) ToEndpointUpdateMap() (map[string]interface{}, error) {
+	return gophercloud.BuildRequestBody(opts, "endpoint")
 }
 
 // Update changes an existing endpoint with new data.
-// All fields are optional in the provided EndpointOpts.
-func Update(client *gophercloud.ServiceClient, endpointID string, opts EndpointOpts) UpdateResult {
-	type endpoint struct {
-		Interface *string `json:"interface,omitempty"`
-		Name      *string `json:"name,omitempty"`
-		Region    *string `json:"region,omitempty"`
-		URL       *string `json:"url,omitempty"`
-		ServiceID *string `json:"service_id,omitempty"`
+func Update(client *gophercloud.ServiceClient, endpointID string, opts UpdateOptsBuilder) UpdateResult {
+	var r UpdateResult
+	b, err := opts.ToEndpointUpdateMap()
+	if err != nil {
+		r.Err = err
+		return r
 	}
-
-	type request struct {
-		Endpoint endpoint `json:"endpoint"`
-	}
-
-	reqBody := request{Endpoint: endpoint{}}
-	reqBody.Endpoint.Interface = gophercloud.MaybeString(string(opts.Availability))
-	reqBody.Endpoint.Name = gophercloud.MaybeString(opts.Name)
-	reqBody.Endpoint.Region = gophercloud.MaybeString(opts.Region)
-	reqBody.Endpoint.URL = gophercloud.MaybeString(opts.URL)
-	reqBody.Endpoint.ServiceID = gophercloud.MaybeString(opts.ServiceID)
-
-	var result UpdateResult
-	_, result.Err = client.Request("PATCH", endpointURL(client, endpointID), &gophercloud.RequestOpts{
-		JSONBody:     &reqBody,
-		JSONResponse: &result.Body,
-		OkCodes:      []int{200},
-	})
-	return result
+	_, r.Err = client.Patch(endpointURL(client, endpointID), &b, &r.Body, nil)
+	return r
 }
 
 // Delete removes an endpoint from the service catalog.
 func Delete(client *gophercloud.ServiceClient, endpointID string) DeleteResult {
-	var res DeleteResult
-	_, res.Err = client.Delete(endpointURL(client, endpointID), nil)
-	return res
+	var r DeleteResult
+	_, r.Err = client.Delete(endpointURL(client, endpointID), nil)
+	return r
 }
diff --git a/openstack/identity/v3/endpoints/requests_test.go b/openstack/identity/v3/endpoints/requests_test.go
index ec17d17..14bbe6a 100644
--- a/openstack/identity/v3/endpoints/requests_test.go
+++ b/openstack/identity/v3/endpoints/requests_test.go
@@ -3,23 +3,22 @@
 import (
 	"fmt"
 	"net/http"
-	"reflect"
 	"testing"
 
 	"github.com/gophercloud/gophercloud"
 	"github.com/gophercloud/gophercloud/pagination"
-	"github.com/gophercloud/gophercloud/testhelper"
+	th "github.com/gophercloud/gophercloud/testhelper"
 	"github.com/gophercloud/gophercloud/testhelper/client"
 )
 
 func TestCreateSuccessful(t *testing.T) {
-	testhelper.SetupHTTP()
-	defer testhelper.TeardownHTTP()
+	th.SetupHTTP()
+	defer th.TeardownHTTP()
 
-	testhelper.Mux.HandleFunc("/endpoints", func(w http.ResponseWriter, r *http.Request) {
-		testhelper.TestMethod(t, r, "POST")
-		testhelper.TestHeader(t, r, "X-Auth-Token", client.TokenID)
-		testhelper.TestJSONRequest(t, r, `
+	th.Mux.HandleFunc("/endpoints", func(w http.ResponseWriter, r *http.Request) {
+		th.TestMethod(t, r, "POST")
+		th.TestHeader(t, r, "X-Auth-Token", client.TokenID)
+		th.TestJSONRequest(t, r, `
       {
         "endpoint": {
           "interface": "public",
@@ -49,16 +48,14 @@
     `)
 	})
 
-	actual, err := Create(client.ServiceClient(), EndpointOpts{
+	actual, err := Create(client.ServiceClient(), CreateOpts{
 		Availability: gophercloud.AvailabilityPublic,
 		Name:         "the-endiest-of-points",
 		Region:       "underground",
 		URL:          "https://1.2.3.4:9000/",
 		ServiceID:    "asdfasdfasdfasdf",
 	}).Extract()
-	if err != nil {
-		t.Fatalf("Unable to create an endpoint: %v", err)
-	}
+	th.AssertNoErr(t, err)
 
 	expected := &Endpoint{
 		ID:           "12",
@@ -69,18 +66,16 @@
 		URL:          "https://1.2.3.4:9000/",
 	}
 
-	if !reflect.DeepEqual(actual, expected) {
-		t.Errorf("Expected %#v, was %#v", expected, actual)
-	}
+	th.AssertDeepEquals(t, expected, actual)
 }
 
 func TestListEndpoints(t *testing.T) {
-	testhelper.SetupHTTP()
-	defer testhelper.TeardownHTTP()
+	th.SetupHTTP()
+	defer th.TeardownHTTP()
 
-	testhelper.Mux.HandleFunc("/endpoints", func(w http.ResponseWriter, r *http.Request) {
-		testhelper.TestMethod(t, r, "GET")
-		testhelper.TestHeader(t, r, "X-Auth-Token", client.TokenID)
+	th.Mux.HandleFunc("/endpoints", func(w http.ResponseWriter, r *http.Request) {
+		th.TestMethod(t, r, "GET")
+		th.TestHeader(t, r, "X-Auth-Token", client.TokenID)
 
 		w.Header().Add("Content-Type", "application/json")
 		fmt.Fprintf(w, `
@@ -144,26 +139,20 @@
 				URL:          "https://1.2.3.4:9001/",
 			},
 		}
-
-		if !reflect.DeepEqual(expected, actual) {
-			t.Errorf("Expected %#v, got %#v", expected, actual)
-		}
-
+		th.AssertDeepEquals(t, expected, actual)
 		return true, nil
 	})
-	if count != 1 {
-		t.Errorf("Expected 1 page, got %d", count)
-	}
+	th.AssertEquals(t, 1, count)
 }
 
 func TestUpdateEndpoint(t *testing.T) {
-	testhelper.SetupHTTP()
-	defer testhelper.TeardownHTTP()
+	th.SetupHTTP()
+	defer th.TeardownHTTP()
 
-	testhelper.Mux.HandleFunc("/endpoints/12", func(w http.ResponseWriter, r *http.Request) {
-		testhelper.TestMethod(t, r, "PATCH")
-		testhelper.TestHeader(t, r, "X-Auth-Token", client.TokenID)
-		testhelper.TestJSONRequest(t, r, `
+	th.Mux.HandleFunc("/endpoints/12", func(w http.ResponseWriter, r *http.Request) {
+		th.TestMethod(t, r, "PATCH")
+		th.TestHeader(t, r, "X-Auth-Token", client.TokenID)
+		th.TestJSONRequest(t, r, `
 		{
 	    "endpoint": {
 	      "name": "renamed",
@@ -189,7 +178,7 @@
 	`)
 	})
 
-	actual, err := Update(client.ServiceClient(), "12", EndpointOpts{
+	actual, err := Update(client.ServiceClient(), "12", UpdateOpts{
 		Name:   "renamed",
 		Region: "somewhere-else",
 	}).Extract()
@@ -205,22 +194,20 @@
 		ServiceID:    "asdfasdfasdfasdf",
 		URL:          "https://1.2.3.4:9000/",
 	}
-	if !reflect.DeepEqual(expected, actual) {
-		t.Errorf("Expected %#v, was %#v", expected, actual)
-	}
+	th.AssertDeepEquals(t, expected, actual)
 }
 
 func TestDeleteEndpoint(t *testing.T) {
-	testhelper.SetupHTTP()
-	defer testhelper.TeardownHTTP()
+	th.SetupHTTP()
+	defer th.TeardownHTTP()
 
-	testhelper.Mux.HandleFunc("/endpoints/34", func(w http.ResponseWriter, r *http.Request) {
-		testhelper.TestMethod(t, r, "DELETE")
-		testhelper.TestHeader(t, r, "X-Auth-Token", client.TokenID)
+	th.Mux.HandleFunc("/endpoints/34", func(w http.ResponseWriter, r *http.Request) {
+		th.TestMethod(t, r, "DELETE")
+		th.TestHeader(t, r, "X-Auth-Token", client.TokenID)
 
 		w.WriteHeader(http.StatusNoContent)
 	})
 
 	res := Delete(client.ServiceClient(), "34")
-	testhelper.AssertNoErr(t, res.Err)
+	th.AssertNoErr(t, res.Err)
 }
diff --git a/openstack/identity/v3/roles/requests.go b/openstack/identity/v3/roles/requests.go
index 0264347..de65c51 100644
--- a/openstack/identity/v3/roles/requests.go
+++ b/openstack/identity/v3/roles/requests.go
@@ -17,34 +17,31 @@
 // Effective lists effective assignments at the user, project, and domain level,
 // allowing for the effects of group membership.
 type ListAssignmentsOpts struct {
-	GroupId        string `q:"group.id"`
-	RoleId         string `q:"role.id"`
-	ScopeDomainId  string `q:"scope.domain.id"`
-	ScopeProjectId string `q:"scope.project.id"`
-	UserId         string `q:"user.id"`
-	Effective      bool   `q:"effective"`
+	GroupID        string `q:"group.id"`
+	RoleID         string `q:"role.id"`
+	ScopeDomainID  string `q:"scope.domain.id"`
+	ScopeProjectID string `q:"scope.project.id"`
+	UserID         string `q:"user.id"`
+	Effective      *bool  `q:"effective"`
 }
 
 // ToRolesListAssignmentsQuery formats a ListAssignmentsOpts into a query string.
 func (opts ListAssignmentsOpts) ToRolesListAssignmentsQuery() (string, error) {
 	q, err := gophercloud.BuildQueryString(opts)
-	if err != nil {
-		return "", err
-	}
-	return q.String(), nil
+	return q.String(), err
 }
 
 // ListAssignments enumerates the roles assigned to a specified resource.
 func ListAssignments(client *gophercloud.ServiceClient, opts ListAssignmentsOptsBuilder) pagination.Pager {
 	url := listAssignmentsURL(client)
-	query, err := opts.ToRolesListAssignmentsQuery()
-	if err != nil {
-		return pagination.Pager{Err: err}
+	if opts != nil {
+		query, err := opts.ToRolesListAssignmentsQuery()
+		if err != nil {
+			return pagination.Pager{Err: err}
+		}
+		url += query
 	}
-	url += query
-	createPage := func(r pagination.PageResult) pagination.Page {
+	return pagination.NewPager(client, url, func(r pagination.PageResult) pagination.Page {
 		return RoleAssignmentPage{pagination.LinkedPageBase{PageResult: r}}
-	}
-
-	return pagination.NewPager(client, url, createPage)
+	})
 }
diff --git a/openstack/identity/v3/services/requests.go b/openstack/identity/v3/services/requests.go
index 484afab..34bf979 100644
--- a/openstack/identity/v3/services/requests.go
+++ b/openstack/identity/v3/services/requests.go
@@ -5,21 +5,16 @@
 	"github.com/gophercloud/gophercloud/pagination"
 )
 
-type response struct {
-	Service Service `json:"service"`
-}
-
 // Create adds a new service of the requested type to the catalog.
 func Create(client *gophercloud.ServiceClient, serviceType string) CreateResult {
-	type request struct {
-		Type string `json:"type"`
-	}
+	var r CreateResult
+	b := map[string]string{"type": serviceType}
+	_, r.Err = client.Post(listURL(client), b, &r.Body, nil)
+	return r
+}
 
-	req := request{Type: serviceType}
-
-	var result CreateResult
-	_, result.Err = client.Post(listURL(client), req, &result.Body, nil)
-	return result
+type ListOptsBuilder interface {
+	ToServiceListMap() (string, error)
 }
 
 // ListOpts allows you to query the List method.
@@ -29,49 +24,45 @@
 	Page        int    `q:"page"`
 }
 
-// List enumerates the services available to a specific user.
-func List(client *gophercloud.ServiceClient, opts ListOpts) pagination.Pager {
-	u := listURL(client)
+func (opts ListOpts) ToServiceListMap() (string, error) {
 	q, err := gophercloud.BuildQueryString(opts)
-	if err != nil {
-		return pagination.Pager{Err: err}
-	}
-	u += q.String()
-	createPage := func(r pagination.PageResult) pagination.Page {
-		return ServicePage{pagination.LinkedPageBase{PageResult: r}}
-	}
+	return q.String(), err
+}
 
-	return pagination.NewPager(client, u, createPage)
+// List enumerates the services available to a specific user.
+func List(client *gophercloud.ServiceClient, opts ListOptsBuilder) pagination.Pager {
+	u := listURL(client)
+	if opts != nil {
+		q, err := opts.ToServiceListMap()
+		if err != nil {
+			return pagination.Pager{Err: err}
+		}
+		u += q
+	}
+	return pagination.NewPager(client, u, func(r pagination.PageResult) pagination.Page {
+		return ServicePage{pagination.LinkedPageBase{PageResult: r}}
+	})
 }
 
 // Get returns additional information about a service, given its ID.
 func Get(client *gophercloud.ServiceClient, serviceID string) GetResult {
-	var result GetResult
-	_, result.Err = client.Get(serviceURL(client, serviceID), &result.Body, nil)
-	return result
+	var r GetResult
+	_, r.Err = client.Get(serviceURL(client, serviceID), &r.Body, nil)
+	return r
 }
 
 // Update changes the service type of an existing service.
 func Update(client *gophercloud.ServiceClient, serviceID string, serviceType string) UpdateResult {
-	type request struct {
-		Type string `json:"type"`
-	}
-
-	req := request{Type: serviceType}
-
-	var result UpdateResult
-	_, result.Err = client.Request("PATCH", serviceURL(client, serviceID), &gophercloud.RequestOpts{
-		JSONBody:     &req,
-		JSONResponse: &result.Body,
-		OkCodes:      []int{200},
-	})
-	return result
+	var r UpdateResult
+	b := map[string]string{"type": serviceType}
+	_, r.Err = client.Patch(serviceURL(client, serviceID), &b, &r.Body, nil)
+	return r
 }
 
 // Delete removes an existing service.
 // It either deletes all associated endpoints, or fails until all endpoints are deleted.
 func Delete(client *gophercloud.ServiceClient, serviceID string) DeleteResult {
-	var res DeleteResult
-	_, res.Err = client.Delete(serviceURL(client, serviceID), nil)
-	return res
+	var r DeleteResult
+	_, r.Err = client.Delete(serviceURL(client, serviceID), nil)
+	return r
 }
diff --git a/openstack/identity/v3/services/requests_test.go b/openstack/identity/v3/services/requests_test.go
index ebe9e0f..aa19bcc 100644
--- a/openstack/identity/v3/services/requests_test.go
+++ b/openstack/identity/v3/services/requests_test.go
@@ -3,22 +3,21 @@
 import (
 	"fmt"
 	"net/http"
-	"reflect"
 	"testing"
 
 	"github.com/gophercloud/gophercloud/pagination"
-	"github.com/gophercloud/gophercloud/testhelper"
+	th "github.com/gophercloud/gophercloud/testhelper"
 	"github.com/gophercloud/gophercloud/testhelper/client"
 )
 
 func TestCreateSuccessful(t *testing.T) {
-	testhelper.SetupHTTP()
-	defer testhelper.TeardownHTTP()
+	th.SetupHTTP()
+	defer th.TeardownHTTP()
 
-	testhelper.Mux.HandleFunc("/services", func(w http.ResponseWriter, r *http.Request) {
-		testhelper.TestMethod(t, r, "POST")
-		testhelper.TestHeader(t, r, "X-Auth-Token", client.TokenID)
-		testhelper.TestJSONRequest(t, r, `{ "type": "compute" }`)
+	th.Mux.HandleFunc("/services", func(w http.ResponseWriter, r *http.Request) {
+		th.TestMethod(t, r, "POST")
+		th.TestHeader(t, r, "X-Auth-Token", client.TokenID)
+		th.TestJSONRequest(t, r, `{ "type": "compute" }`)
 
 		w.Header().Add("Content-Type", "application/json")
 		w.WriteHeader(http.StatusCreated)
@@ -32,32 +31,27 @@
     }`)
 	})
 
-	result, err := Create(client.ServiceClient(), "compute").Extract()
+	expected := &Service{
+		Description: "Here's your service",
+		ID:          "1234",
+		Name:        "InscrutableOpenStackProjectName",
+		Type:        "compute",
+	}
+
+	actual, err := Create(client.ServiceClient(), "compute").Extract()
 	if err != nil {
 		t.Fatalf("Unexpected error from Create: %v", err)
 	}
-
-	if result.Description == nil || *result.Description != "Here's your service" {
-		t.Errorf("Service description was unexpected [%s]", *result.Description)
-	}
-	if result.ID != "1234" {
-		t.Errorf("Service ID was unexpected [%s]", result.ID)
-	}
-	if result.Name != "InscrutableOpenStackProjectName" {
-		t.Errorf("Service name was unexpected [%s]", result.Name)
-	}
-	if result.Type != "compute" {
-		t.Errorf("Service type was unexpected [%s]", result.Type)
-	}
+	th.AssertDeepEquals(t, expected, actual)
 }
 
 func TestListSinglePage(t *testing.T) {
-	testhelper.SetupHTTP()
-	defer testhelper.TeardownHTTP()
+	th.SetupHTTP()
+	defer th.TeardownHTTP()
 
-	testhelper.Mux.HandleFunc("/services", func(w http.ResponseWriter, r *http.Request) {
-		testhelper.TestMethod(t, r, "GET")
-		testhelper.TestHeader(t, r, "X-Auth-Token", client.TokenID)
+	th.Mux.HandleFunc("/services", func(w http.ResponseWriter, r *http.Request) {
+		th.TestMethod(t, r, "GET")
+		th.TestHeader(t, r, "X-Auth-Token", client.TokenID)
 
 		w.Header().Add("Content-Type", "application/json")
 		fmt.Fprintf(w, `
@@ -92,44 +86,34 @@
 			return false, err
 		}
 
-		desc0 := "Service One"
-		desc1 := "Service Two"
 		expected := []Service{
 			Service{
-				Description: &desc0,
+				Description: "Service One",
 				ID:          "1234",
 				Name:        "service-one",
 				Type:        "identity",
 			},
 			Service{
-				Description: &desc1,
+				Description: "Service Two",
 				ID:          "9876",
 				Name:        "service-two",
 				Type:        "compute",
 			},
 		}
-
-		if !reflect.DeepEqual(expected, actual) {
-			t.Errorf("Expected %#v, got %#v", expected, actual)
-		}
-
+		th.AssertDeepEquals(t, expected, actual)
 		return true, nil
 	})
-	if err != nil {
-		t.Errorf("Unexpected error while paging: %v", err)
-	}
-	if count != 1 {
-		t.Errorf("Expected 1 page, got %d", count)
-	}
+	th.AssertNoErr(t, err)
+	th.AssertEquals(t, 1, count)
 }
 
 func TestGetSuccessful(t *testing.T) {
-	testhelper.SetupHTTP()
-	defer testhelper.TeardownHTTP()
+	th.SetupHTTP()
+	defer th.TeardownHTTP()
 
-	testhelper.Mux.HandleFunc("/services/12345", func(w http.ResponseWriter, r *http.Request) {
-		testhelper.TestMethod(t, r, "GET")
-		testhelper.TestHeader(t, r, "X-Auth-Token", client.TokenID)
+	th.Mux.HandleFunc("/services/12345", func(w http.ResponseWriter, r *http.Request) {
+		th.TestMethod(t, r, "GET")
+		th.TestHeader(t, r, "X-Auth-Token", client.TokenID)
 
 		w.Header().Add("Content-Type", "application/json")
 		fmt.Fprintf(w, `
@@ -144,33 +128,27 @@
 		`)
 	})
 
-	result, err := Get(client.ServiceClient(), "12345").Extract()
-	if err != nil {
-		t.Fatalf("Error fetching service information: %v", err)
+	actual, err := Get(client.ServiceClient(), "12345").Extract()
+	th.AssertNoErr(t, err)
+
+	expected := &Service{
+		ID:          "12345",
+		Description: "Service One",
+		Name:        "service-one",
+		Type:        "identity",
 	}
 
-	if result.ID != "12345" {
-		t.Errorf("Unexpected service ID: %s", result.ID)
-	}
-	if *result.Description != "Service One" {
-		t.Errorf("Unexpected service description: [%s]", *result.Description)
-	}
-	if result.Name != "service-one" {
-		t.Errorf("Unexpected service name: [%s]", result.Name)
-	}
-	if result.Type != "identity" {
-		t.Errorf("Unexpected service type: [%s]", result.Type)
-	}
+	th.AssertDeepEquals(t, expected, actual)
 }
 
 func TestUpdateSuccessful(t *testing.T) {
-	testhelper.SetupHTTP()
-	defer testhelper.TeardownHTTP()
+	th.SetupHTTP()
+	defer th.TeardownHTTP()
 
-	testhelper.Mux.HandleFunc("/services/12345", func(w http.ResponseWriter, r *http.Request) {
-		testhelper.TestMethod(t, r, "PATCH")
-		testhelper.TestHeader(t, r, "X-Auth-Token", client.TokenID)
-		testhelper.TestJSONRequest(t, r, `{ "type": "lasermagic" }`)
+	th.Mux.HandleFunc("/services/12345", func(w http.ResponseWriter, r *http.Request) {
+		th.TestMethod(t, r, "PATCH")
+		th.TestHeader(t, r, "X-Auth-Token", client.TokenID)
+		th.TestJSONRequest(t, r, `{ "type": "lasermagic" }`)
 
 		w.Header().Add("Content-Type", "application/json")
 		fmt.Fprintf(w, `
@@ -183,27 +161,26 @@
 		`)
 	})
 
-	result, err := Update(client.ServiceClient(), "12345", "lasermagic").Extract()
-	if err != nil {
-		t.Fatalf("Unable to update service: %v", err)
+	expected := &Service{
+		ID:   "12345",
+		Type: "lasermagic",
 	}
 
-	if result.ID != "12345" {
-		t.Fatalf("Expected ID 12345, was %s", result.ID)
-	}
+	actual, err := Update(client.ServiceClient(), "12345", "lasermagic").Extract()
+	th.AssertNoErr(t, err)
+	th.AssertDeepEquals(t, expected, actual)
 }
 
 func TestDeleteSuccessful(t *testing.T) {
-	testhelper.SetupHTTP()
-	defer testhelper.TeardownHTTP()
+	th.SetupHTTP()
+	defer th.TeardownHTTP()
 
-	testhelper.Mux.HandleFunc("/services/12345", func(w http.ResponseWriter, r *http.Request) {
-		testhelper.TestMethod(t, r, "DELETE")
-		testhelper.TestHeader(t, r, "X-Auth-Token", client.TokenID)
-
+	th.Mux.HandleFunc("/services/12345", func(w http.ResponseWriter, r *http.Request) {
+		th.TestMethod(t, r, "DELETE")
+		th.TestHeader(t, r, "X-Auth-Token", client.TokenID)
 		w.WriteHeader(http.StatusNoContent)
 	})
 
 	res := Delete(client.ServiceClient(), "12345")
-	testhelper.AssertNoErr(t, res.Err)
+	th.AssertNoErr(t, res.Err)
 }
diff --git a/openstack/identity/v3/services/results.go b/openstack/identity/v3/services/results.go
index b0d36fb..9ebcc20 100644
--- a/openstack/identity/v3/services/results.go
+++ b/openstack/identity/v3/services/results.go
@@ -41,10 +41,10 @@
 
 // Service is the result of a list or information query.
 type Service struct {
-	Description *string `json:"description,omitempty"`
-	ID          string  `json:"id"`
-	Name        string  `json:"name"`
-	Type        string  `json:"type"`
+	Description string `json:"description`
+	ID          string `json:"id"`
+	Name        string `json:"name"`
+	Type        string `json:"type"`
 }
 
 // ServicePage is a single page of Service results.
diff --git a/openstack/identity/v3/tokens/requests.go b/openstack/identity/v3/tokens/requests.go
index 4b87311..e7320fd 100644
--- a/openstack/identity/v3/tokens/requests.go
+++ b/openstack/identity/v3/tokens/requests.go
@@ -6,12 +6,11 @@
 	"github.com/gophercloud/gophercloud"
 )
 
-// Scope allows a created token to be limited to a specific domain or project.
-type Scope struct {
-	ProjectID   string
-	ProjectName string
-	DomainID    string
-	DomainName  string
+// AuthOptionsBuilder describes any argument that may be passed to the Create call.
+type AuthOptionsBuilder interface {
+	// ToTokenV3CreateMap assembles the Create request body, returning an error if parameters are
+	// missing or inconsistent.
+	ToTokenV3CreateMap(*gophercloud.ScopeOptsV3) (map[string]interface{}, error)
 }
 
 func subjectTokenHeaders(c *gophercloud.ServiceClient, subjectToken string) map[string]string {
@@ -21,241 +20,33 @@
 }
 
 // Create authenticates and either generates a new token, or changes the Scope of an existing token.
-func Create(c *gophercloud.ServiceClient, options gophercloud.AuthOptions, scope *Scope) CreateResult {
-	type domainReq struct {
-		ID   *string `json:"id,omitempty"`
-		Name *string `json:"name,omitempty"`
+func Create(c *gophercloud.ServiceClient, opts AuthOptionsBuilder, scopeOpts *gophercloud.ScopeOptsV3) CreateResult {
+	var r CreateResult
+	b, err := opts.ToTokenV3CreateMap(scopeOpts)
+	if err != nil {
+		r.Err = err
+		return r
 	}
-
-	type projectReq struct {
-		Domain *domainReq `json:"domain,omitempty"`
-		Name   *string    `json:"name,omitempty"`
-		ID     *string    `json:"id,omitempty"`
+	var resp *http.Response
+	resp, r.Err = c.Post(tokenURL(c), b, &r.Body, nil)
+	if resp != nil {
+		r.Header = resp.Header
 	}
-
-	type userReq struct {
-		ID       *string    `json:"id,omitempty"`
-		Name     *string    `json:"name,omitempty"`
-		Password string     `json:"password"`
-		Domain   *domainReq `json:"domain,omitempty"`
-	}
-
-	type passwordReq struct {
-		User userReq `json:"user"`
-	}
-
-	type tokenReq struct {
-		ID string `json:"id"`
-	}
-
-	type identityReq struct {
-		Methods  []string     `json:"methods"`
-		Password *passwordReq `json:"password,omitempty"`
-		Token    *tokenReq    `json:"token,omitempty"`
-	}
-
-	type scopeReq struct {
-		Domain  *domainReq  `json:"domain,omitempty"`
-		Project *projectReq `json:"project,omitempty"`
-	}
-
-	type authReq struct {
-		Identity identityReq `json:"identity"`
-		Scope    *scopeReq   `json:"scope,omitempty"`
-	}
-
-	type request struct {
-		Auth authReq `json:"auth"`
-	}
-
-	// Populate the request structure based on the provided arguments. Create and return an error
-	// if insufficient or incompatible information is present.
-	var req request
-
-	// Test first for unrecognized arguments.
-	if options.APIKey != "" {
-		return createErr(ErrAPIKeyProvided)
-	}
-	if options.TenantID != "" {
-		return createErr(ErrTenantIDProvided)
-	}
-	if options.TenantName != "" {
-		return createErr(ErrTenantNameProvided)
-	}
-
-	if options.Password == "" {
-		if c.TokenID != "" {
-			// Because we aren't using password authentication, it's an error to also provide any of the user-based authentication
-			// parameters.
-			if options.Username != "" {
-				return createErr(ErrUsernameWithToken)
-			}
-			if options.UserID != "" {
-				return createErr(ErrUserIDWithToken)
-			}
-			if options.DomainID != "" {
-				return createErr(ErrDomainIDWithToken)
-			}
-			if options.DomainName != "" {
-				return createErr(ErrDomainNameWithToken)
-			}
-
-			// Configure the request for Token authentication.
-			req.Auth.Identity.Methods = []string{"token"}
-			req.Auth.Identity.Token = &tokenReq{
-				ID: c.TokenID,
-			}
-		} else {
-			// If no password or token ID are available, authentication can't continue.
-			return createErr(ErrMissingPassword)
-		}
-	} else {
-		// Password authentication.
-		req.Auth.Identity.Methods = []string{"password"}
-
-		// At least one of Username and UserID must be specified.
-		if options.Username == "" && options.UserID == "" {
-			return createErr(ErrUsernameOrUserID)
-		}
-
-		if options.Username != "" {
-			// If Username is provided, UserID may not be provided.
-			if options.UserID != "" {
-				return createErr(ErrUsernameOrUserID)
-			}
-
-			// Either DomainID or DomainName must also be specified.
-			if options.DomainID == "" && options.DomainName == "" {
-				return createErr(ErrDomainIDOrDomainName)
-			}
-
-			if options.DomainID != "" {
-				if options.DomainName != "" {
-					return createErr(ErrDomainIDOrDomainName)
-				}
-
-				// Configure the request for Username and Password authentication with a DomainID.
-				req.Auth.Identity.Password = &passwordReq{
-					User: userReq{
-						Name:     &options.Username,
-						Password: options.Password,
-						Domain:   &domainReq{ID: &options.DomainID},
-					},
-				}
-			}
-
-			if options.DomainName != "" {
-				// Configure the request for Username and Password authentication with a DomainName.
-				req.Auth.Identity.Password = &passwordReq{
-					User: userReq{
-						Name:     &options.Username,
-						Password: options.Password,
-						Domain:   &domainReq{Name: &options.DomainName},
-					},
-				}
-			}
-		}
-
-		if options.UserID != "" {
-			// If UserID is specified, neither DomainID nor DomainName may be.
-			if options.DomainID != "" {
-				return createErr(ErrDomainIDWithUserID)
-			}
-			if options.DomainName != "" {
-				return createErr(ErrDomainNameWithUserID)
-			}
-
-			// Configure the request for UserID and Password authentication.
-			req.Auth.Identity.Password = &passwordReq{
-				User: userReq{ID: &options.UserID, Password: options.Password},
-			}
-		}
-	}
-
-	// Add a "scope" element if a Scope has been provided.
-	if scope != nil {
-		if scope.ProjectName != "" {
-			// ProjectName provided: either DomainID or DomainName must also be supplied.
-			// ProjectID may not be supplied.
-			if scope.DomainID == "" && scope.DomainName == "" {
-				return createErr(ErrScopeDomainIDOrDomainName)
-			}
-			if scope.ProjectID != "" {
-				return createErr(ErrScopeProjectIDOrProjectName)
-			}
-
-			if scope.DomainID != "" {
-				// ProjectName + DomainID
-				req.Auth.Scope = &scopeReq{
-					Project: &projectReq{
-						Name:   &scope.ProjectName,
-						Domain: &domainReq{ID: &scope.DomainID},
-					},
-				}
-			}
-
-			if scope.DomainName != "" {
-				// ProjectName + DomainName
-				req.Auth.Scope = &scopeReq{
-					Project: &projectReq{
-						Name:   &scope.ProjectName,
-						Domain: &domainReq{Name: &scope.DomainName},
-					},
-				}
-			}
-		} else if scope.ProjectID != "" {
-			// ProjectID provided. ProjectName, DomainID, and DomainName may not be provided.
-			if scope.DomainID != "" {
-				return createErr(ErrScopeProjectIDAlone)
-			}
-			if scope.DomainName != "" {
-				return createErr(ErrScopeProjectIDAlone)
-			}
-
-			// ProjectID
-			req.Auth.Scope = &scopeReq{
-				Project: &projectReq{ID: &scope.ProjectID},
-			}
-		} else if scope.DomainID != "" {
-			// DomainID provided. ProjectID, ProjectName, and DomainName may not be provided.
-			if scope.DomainName != "" {
-				return createErr(ErrScopeDomainIDOrDomainName)
-			}
-
-			// DomainID
-			req.Auth.Scope = &scopeReq{
-				Domain: &domainReq{ID: &scope.DomainID},
-			}
-		} else if scope.DomainName != "" {
-			return createErr(ErrScopeDomainName)
-		} else {
-			return createErr(ErrScopeEmpty)
-		}
-	}
-
-	var result CreateResult
-	var response *http.Response
-	response, result.Err = c.Post(tokenURL(c), req, &result.Body, nil)
-	if result.Err != nil {
-		return result
-	}
-	result.Header = response.Header
-	return result
+	return r
 }
 
 // Get validates and retrieves information about another token.
 func Get(c *gophercloud.ServiceClient, token string) GetResult {
-	var result GetResult
-	var response *http.Response
-	response, result.Err = c.Get(tokenURL(c), &result.Body, &gophercloud.RequestOpts{
+	var r GetResult
+	var resp *http.Response
+	resp, r.Err = c.Get(tokenURL(c), &r.Body, &gophercloud.RequestOpts{
 		MoreHeaders: subjectTokenHeaders(c, token),
 		OkCodes:     []int{200, 203},
 	})
-	if result.Err != nil {
-		return result
+	if resp != nil {
+		r.Header = resp.Header
 	}
-	result.Header = response.Header
-	return result
+	return r
 }
 
 // Validate determines if a specified token is valid or not.
@@ -273,9 +64,9 @@
 
 // Revoke immediately makes specified token invalid.
 func Revoke(c *gophercloud.ServiceClient, token string) RevokeResult {
-	var res RevokeResult
-	_, res.Err = c.Delete(tokenURL(c), &gophercloud.RequestOpts{
+	var r RevokeResult
+	_, r.Err = c.Delete(tokenURL(c), &gophercloud.RequestOpts{
 		MoreHeaders: subjectTokenHeaders(c, token),
 	})
-	return res
+	return r
 }
diff --git a/openstack/identity/v3/tokens/requests_test.go b/openstack/identity/v3/tokens/requests_test.go
index 89d3b51..a39a6f4 100644
--- a/openstack/identity/v3/tokens/requests_test.go
+++ b/openstack/identity/v3/tokens/requests_test.go
@@ -11,7 +11,7 @@
 )
 
 // authTokenPost verifies that providing certain AuthOptions and Scope results in an expected JSON structure.
-func authTokenPost(t *testing.T, options gophercloud.AuthOptions, scope *Scope, requestJSON string) {
+func authTokenPost(t *testing.T, options AuthOptionsBuilder, scope *gophercloud.ScopeOptsV3, requestJSON string) {
 	testhelper.SetupHTTP()
 	defer testhelper.TeardownHTTP()
 
@@ -42,7 +42,7 @@
 	}
 }
 
-func authTokenPostErr(t *testing.T, options gophercloud.AuthOptions, scope *Scope, includeToken bool, expectedErr error) {
+func authTokenPostErr(t *testing.T, options AuthOptionsBuilder, scope *gophercloud.ScopeOptsV3, includeToken bool, expectedErr error) {
 	testhelper.SetupHTTP()
 	defer testhelper.TeardownHTTP()
 
@@ -64,7 +64,10 @@
 }
 
 func TestCreateUserIDAndPassword(t *testing.T) {
-	authTokenPost(t, gophercloud.AuthOptions{UserID: "me", Password: "squirrel!"}, nil, `
+	ao := gophercloud.AuthOptions{}
+	ao.UserID = "me"
+	ao.Password = "squirrel!"
+	authTokenPost(t, ao, nil, `
 		{
 			"auth": {
 				"identity": {
@@ -79,7 +82,10 @@
 }
 
 func TestCreateUsernameDomainIDPassword(t *testing.T) {
-	authTokenPost(t, gophercloud.AuthOptions{Username: "fakey", Password: "notpassword", DomainID: "abc123"}, nil, `
+	ao := gophercloud.AuthOptions{DomainID: "abc123"}
+	ao.Username = "fakey"
+	ao.Password = "notpassword"
+	authTokenPost(t, ao, nil, `
 		{
 			"auth": {
 				"identity": {
@@ -100,7 +106,10 @@
 }
 
 func TestCreateUsernameDomainNamePassword(t *testing.T) {
-	authTokenPost(t, gophercloud.AuthOptions{Username: "frank", Password: "swordfish", DomainName: "spork.net"}, nil, `
+	ao := gophercloud.AuthOptions{DomainName: "spork.net"}
+	ao.Username = "frank"
+	ao.Password = "swordfish"
+	authTokenPost(t, ao, nil, `
 		{
 			"auth": {
 				"identity": {
@@ -121,7 +130,7 @@
 }
 
 func TestCreateTokenID(t *testing.T) {
-	authTokenPost(t, gophercloud.AuthOptions{}, nil, `
+	authTokenPost(t, gophercloud.AuthOptions{TokenID: "12345abcdef"}, nil, `
 		{
 			"auth": {
 				"identity": {
@@ -136,9 +145,11 @@
 }
 
 func TestCreateProjectIDScope(t *testing.T) {
-	options := gophercloud.AuthOptions{UserID: "fenris", Password: "g0t0h311"}
-	scope := &Scope{ProjectID: "123456"}
-	authTokenPost(t, options, scope, `
+	ao := gophercloud.AuthOptions{}
+	ao.UserID = "fenris"
+	ao.Password = "g0t0h311"
+	scope := &gophercloud.ScopeOptsV3{ProjectID: "123456"}
+	authTokenPost(t, ao, scope, `
 		{
 			"auth": {
 				"identity": {
@@ -161,9 +172,11 @@
 }
 
 func TestCreateDomainIDScope(t *testing.T) {
-	options := gophercloud.AuthOptions{UserID: "fenris", Password: "g0t0h311"}
-	scope := &Scope{DomainID: "1000"}
-	authTokenPost(t, options, scope, `
+	ao := gophercloud.AuthOptions{}
+	ao.UserID = "fenris"
+	ao.Password = "g0t0h311"
+	scope := &gophercloud.ScopeOptsV3{DomainID: "1000"}
+	authTokenPost(t, ao, scope, `
 		{
 			"auth": {
 				"identity": {
@@ -186,9 +199,11 @@
 }
 
 func TestCreateProjectNameAndDomainIDScope(t *testing.T) {
-	options := gophercloud.AuthOptions{UserID: "fenris", Password: "g0t0h311"}
-	scope := &Scope{ProjectName: "world-domination", DomainID: "1000"}
-	authTokenPost(t, options, scope, `
+	ao := gophercloud.AuthOptions{}
+	ao.UserID = "fenris"
+	ao.Password = "g0t0h311"
+	scope := &gophercloud.ScopeOptsV3{ProjectName: "world-domination", DomainID: "1000"}
+	authTokenPost(t, ao, scope, `
 		{
 			"auth": {
 				"identity": {
@@ -214,9 +229,11 @@
 }
 
 func TestCreateProjectNameAndDomainNameScope(t *testing.T) {
-	options := gophercloud.AuthOptions{UserID: "fenris", Password: "g0t0h311"}
-	scope := &Scope{ProjectName: "world-domination", DomainName: "evil-plans"}
-	authTokenPost(t, options, scope, `
+	ao := gophercloud.AuthOptions{}
+	ao.UserID = "fenris"
+	ao.Password = "g0t0h311"
+	scope := &gophercloud.ScopeOptsV3{ProjectName: "world-domination", DomainName: "evil-plans"}
+	authTokenPost(t, ao, scope, `
 		{
 			"auth": {
 				"identity": {
@@ -261,8 +278,10 @@
 		}`)
 	})
 
-	options := gophercloud.AuthOptions{UserID: "me", Password: "shhh"}
-	token, err := Create(&client, options, nil).Extract()
+	ao := gophercloud.AuthOptions{}
+	ao.UserID = "me"
+	ao.Password = "shhh"
+	token, err := Create(&client, ao, nil).Extract()
 	if err != nil {
 		t.Fatalf("Create returned an error: %v", err)
 	}
@@ -276,20 +295,10 @@
 	authTokenPostErr(t, gophercloud.AuthOptions{}, nil, false, ErrMissingPassword)
 }
 
-func TestCreateFailureAPIKey(t *testing.T) {
-	authTokenPostErr(t, gophercloud.AuthOptions{APIKey: "something"}, nil, false, ErrAPIKeyProvided)
-}
-
-func TestCreateFailureTenantID(t *testing.T) {
-	authTokenPostErr(t, gophercloud.AuthOptions{TenantID: "something"}, nil, false, ErrTenantIDProvided)
-}
-
-func TestCreateFailureTenantName(t *testing.T) {
-	authTokenPostErr(t, gophercloud.AuthOptions{TenantName: "something"}, nil, false, ErrTenantNameProvided)
-}
-
 func TestCreateFailureTokenIDUsername(t *testing.T) {
-	authTokenPostErr(t, gophercloud.AuthOptions{Username: "something"}, nil, true, ErrUsernameWithToken)
+	ao := gophercloud.AuthOptions{}
+	ao.Username = "somthing"
+	authTokenPostErr(t, ao, nil, true, ErrUsernameWithToken)
 }
 
 func TestCreateFailureTokenIDUserID(t *testing.T) {
@@ -305,95 +314,105 @@
 }
 
 func TestCreateFailureMissingUser(t *testing.T) {
-	options := gophercloud.AuthOptions{Password: "supersecure"}
-	authTokenPostErr(t, options, nil, false, ErrUsernameOrUserID)
+	ao := gophercloud.AuthOptions{}
+	ao.Password = "supersecure"
+	authTokenPostErr(t, ao, nil, false, ErrUsernameOrUserID)
 }
 
 func TestCreateFailureBothUser(t *testing.T) {
-	options := gophercloud.AuthOptions{
-		Password: "supersecure",
-		Username: "oops",
-		UserID:   "redundancy",
-	}
-	authTokenPostErr(t, options, nil, false, ErrUsernameOrUserID)
+	ao := gophercloud.AuthOptions{}
+	ao.UserID = "redundancy"
+	ao.Username = "oops"
+	ao.Password = "supersecure"
+	authTokenPostErr(t, ao, nil, false, ErrUsernameOrUserID)
 }
 
 func TestCreateFailureMissingDomain(t *testing.T) {
-	options := gophercloud.AuthOptions{
-		Password: "supersecure",
-		Username: "notuniqueenough",
-	}
-	authTokenPostErr(t, options, nil, false, ErrDomainIDOrDomainName)
+	ao := gophercloud.AuthOptions{}
+	ao.Username = "notuniqueenough"
+	ao.Password = "supersecure"
+	authTokenPostErr(t, ao, nil, false, ErrDomainIDOrDomainName)
 }
 
 func TestCreateFailureBothDomain(t *testing.T) {
-	options := gophercloud.AuthOptions{
-		Password:   "supersecure",
-		Username:   "someone",
-		DomainID:   "hurf",
-		DomainName: "durf",
-	}
-	authTokenPostErr(t, options, nil, false, ErrDomainIDOrDomainName)
+	ao := gophercloud.AuthOptions{}
+	ao.Username = "someone"
+	ao.Password = "supersecure"
+	ao.DomainID = "hurf"
+	ao.DomainName = "durf"
+	authTokenPostErr(t, ao, nil, false, ErrDomainIDOrDomainName)
 }
 
 func TestCreateFailureUserIDDomainID(t *testing.T) {
-	options := gophercloud.AuthOptions{
-		UserID:   "100",
-		Password: "stuff",
-		DomainID: "oops",
-	}
-	authTokenPostErr(t, options, nil, false, ErrDomainIDWithUserID)
+	ao := gophercloud.AuthOptions{}
+	ao.UserID = "100"
+	ao.Password = "stuff"
+	ao.DomainID = "oops"
+	authTokenPostErr(t, ao, nil, false, ErrDomainIDWithUserID)
 }
 
 func TestCreateFailureUserIDDomainName(t *testing.T) {
-	options := gophercloud.AuthOptions{
-		UserID:     "100",
-		Password:   "sssh",
-		DomainName: "oops",
-	}
-	authTokenPostErr(t, options, nil, false, ErrDomainNameWithUserID)
+	ao := gophercloud.AuthOptions{}
+	ao.UserID = "100"
+	ao.Password = "sssh"
+	ao.DomainName = "oops"
+	authTokenPostErr(t, ao, nil, false, ErrDomainNameWithUserID)
 }
 
 func TestCreateFailureScopeProjectNameAlone(t *testing.T) {
-	options := gophercloud.AuthOptions{UserID: "myself", Password: "swordfish"}
-	scope := &Scope{ProjectName: "notenough"}
-	authTokenPostErr(t, options, scope, false, ErrScopeDomainIDOrDomainName)
+	ao := gophercloud.AuthOptions{}
+	ao.UserID = "myself"
+	ao.Password = "swordfish"
+	scope := &gophercloud.ScopeOptsV3{ProjectName: "notenough"}
+	authTokenPostErr(t, ao, scope, false, ErrScopeDomainIDOrDomainName)
 }
 
 func TestCreateFailureScopeProjectNameAndID(t *testing.T) {
-	options := gophercloud.AuthOptions{UserID: "myself", Password: "swordfish"}
-	scope := &Scope{ProjectName: "whoops", ProjectID: "toomuch", DomainID: "1234"}
-	authTokenPostErr(t, options, scope, false, ErrScopeProjectIDOrProjectName)
+	ao := gophercloud.AuthOptions{}
+	ao.UserID = "myself"
+	ao.Password = "swordfish"
+	scope := &gophercloud.ScopeOptsV3{ProjectName: "whoops", ProjectID: "toomuch", DomainID: "1234"}
+	authTokenPostErr(t, ao, scope, false, ErrScopeProjectIDOrProjectName)
 }
 
 func TestCreateFailureScopeProjectIDAndDomainID(t *testing.T) {
-	options := gophercloud.AuthOptions{UserID: "myself", Password: "swordfish"}
-	scope := &Scope{ProjectID: "toomuch", DomainID: "notneeded"}
-	authTokenPostErr(t, options, scope, false, ErrScopeProjectIDAlone)
+	ao := gophercloud.AuthOptions{}
+	ao.UserID = "myself"
+	ao.Password = "swordfish"
+	scope := &gophercloud.ScopeOptsV3{ProjectID: "toomuch", DomainID: "notneeded"}
+	authTokenPostErr(t, ao, scope, false, ErrScopeProjectIDAlone)
 }
 
 func TestCreateFailureScopeProjectIDAndDomainNAme(t *testing.T) {
-	options := gophercloud.AuthOptions{UserID: "myself", Password: "swordfish"}
-	scope := &Scope{ProjectID: "toomuch", DomainName: "notneeded"}
-	authTokenPostErr(t, options, scope, false, ErrScopeProjectIDAlone)
+	ao := gophercloud.AuthOptions{}
+	ao.UserID = "myself"
+	ao.Password = "swordfish"
+	scope := &gophercloud.ScopeOptsV3{ProjectID: "toomuch", DomainName: "notneeded"}
+	authTokenPostErr(t, ao, scope, false, ErrScopeProjectIDAlone)
 }
 
 func TestCreateFailureScopeDomainIDAndDomainName(t *testing.T) {
-	options := gophercloud.AuthOptions{UserID: "myself", Password: "swordfish"}
-	scope := &Scope{DomainID: "toomuch", DomainName: "notneeded"}
-	authTokenPostErr(t, options, scope, false, ErrScopeDomainIDOrDomainName)
+	ao := gophercloud.AuthOptions{}
+	ao.UserID = "myself"
+	ao.Password = "swordfish"
+	scope := &gophercloud.ScopeOptsV3{DomainID: "toomuch", DomainName: "notneeded"}
+	authTokenPostErr(t, ao, scope, false, ErrScopeDomainIDOrDomainName)
 }
 
 func TestCreateFailureScopeDomainNameAlone(t *testing.T) {
-	options := gophercloud.AuthOptions{UserID: "myself", Password: "swordfish"}
-	scope := &Scope{DomainName: "notenough"}
-	authTokenPostErr(t, options, scope, false, ErrScopeDomainName)
+	ao := gophercloud.AuthOptions{}
+	ao.UserID = "myself"
+	ao.Password = "swordfish"
+	scope := &gophercloud.ScopeOptsV3{DomainName: "notenough"}
+	authTokenPostErr(t, ao, scope, false, ErrScopeDomainName)
 }
 
 func TestCreateFailureEmptyScope(t *testing.T) {
-	options := gophercloud.AuthOptions{UserID: "myself", Password: "swordfish"}
-	scope := &Scope{}
-	authTokenPostErr(t, options, scope, false, ErrScopeEmpty)
+	ao := gophercloud.AuthOptions{}
+	ao.UserID = "myself"
+	ao.Password = "swordfish"
+	scope := &gophercloud.ScopeOptsV3{}
+	authTokenPostErr(t, ao, scope, false, ErrScopeEmpty)
 }
 
 func TestGetRequest(t *testing.T) {