And all of the rest of the token operations.

Plus tests for each.
diff --git a/openstack/identity/v3/tokens/requests.go b/openstack/identity/v3/tokens/requests.go
index b8f0d76..ab84d81 100644
--- a/openstack/identity/v3/tokens/requests.go
+++ b/openstack/identity/v3/tokens/requests.go
@@ -13,6 +13,12 @@
 	DomainName  string
 }
 
+func subjectTokenHeaders(c *gophercloud.ServiceClient, subjectToken string) map[string]string {
+	h := c.AuthenticatedHeaders()
+	h["X-Subject-Token"] = subjectToken
+	return h
+}
+
 // Create authenticates and either generates a new token, or changes the Scope of an existing token.
 func Create(c *gophercloud.ServiceClient, scope *Scope) (gophercloud.AuthResults, error) {
 	type domainReq struct {
@@ -243,3 +249,45 @@
 
 	return &result, nil
 }
+
+// Info validates and retrieves information about another token.
+func Info(c *gophercloud.ServiceClient, token string) (*TokenCreateResult, error) {
+	var result TokenCreateResult
+
+	response, err := perigee.Request("GET", getTokenURL(c), perigee.Options{
+		MoreHeaders: subjectTokenHeaders(c, token),
+		Results:     &result.response,
+		OkCodes:     []int{200, 203},
+	})
+
+	if err != nil {
+		return nil, err
+	}
+
+	// Extract the token ID from the response, if present.
+	result.tokenID = response.HttpResponse.Header.Get("X-Subject-Token")
+
+	return &result, nil
+}
+
+// Validate determines if a specified token is valid or not.
+func Validate(c *gophercloud.ServiceClient, token string) (bool, error) {
+	response, err := perigee.Request("HEAD", getTokenURL(c), perigee.Options{
+		MoreHeaders: subjectTokenHeaders(c, token),
+		OkCodes:     []int{204, 404},
+	})
+	if err != nil {
+		return false, err
+	}
+
+	return response.StatusCode == 204, nil
+}
+
+// Revoke immediately makes specified token invalid.
+func Revoke(c *gophercloud.ServiceClient, token string) error {
+	_, err := perigee.Request("DELETE", getTokenURL(c), perigee.Options{
+		MoreHeaders: subjectTokenHeaders(c, token),
+		OkCodes:     []int{204},
+	})
+	return err
+}