dsl struct tags; wip
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
 }