And all of the rest of the token operations.

Plus tests for each.
diff --git a/openstack/identity/v3/tokens/doc.go b/openstack/identity/v3/tokens/doc.go
new file mode 100644
index 0000000..02fce0d
--- /dev/null
+++ b/openstack/identity/v3/tokens/doc.go
@@ -0,0 +1,6 @@
+/*
+Package tokens defines operations performed on the token resource.
+
+Documentation: http://developer.openstack.org/api-ref-identity-v3.html#tokens-v3
+*/
+package tokens
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
+}
diff --git a/openstack/identity/v3/tokens/requests_test.go b/openstack/identity/v3/tokens/requests_test.go
index 6038f96..db0fba7 100644
--- a/openstack/identity/v3/tokens/requests_test.go
+++ b/openstack/identity/v3/tokens/requests_test.go
@@ -4,6 +4,7 @@
 	"fmt"
 	"net/http"
 	"testing"
+	"time"
 
 	"github.com/rackspace/gophercloud"
 	"github.com/rackspace/gophercloud/testhelper"
@@ -385,3 +386,123 @@
 	scope := &Scope{}
 	authTokenPostErr(t, options, scope, false, ErrScopeEmpty)
 }
+
+func TestInfoRequest(t *testing.T) {
+	setup()
+	defer teardown()
+
+	client := gophercloud.ServiceClient{
+		Endpoint: endpoint(),
+		TokenID:  "12345abcdef",
+	}
+
+	mux.HandleFunc("/auth/tokens", func(w http.ResponseWriter, r *http.Request) {
+		testhelper.TestMethod(t, r, "GET")
+		testhelper.TestHeader(t, r, "Content-Type", "application/json")
+		testhelper.TestHeader(t, r, "Accept", "application/json")
+		testhelper.TestHeader(t, r, "X-Auth-Token", "12345abcdef")
+		testhelper.TestHeader(t, r, "X-Subject-Token", "abcdef12345")
+
+		w.WriteHeader(http.StatusOK)
+		fmt.Fprintf(w, `
+			{ "token": { "expires_at": "2014-08-29T13:10:01.000000Z" } }
+		`)
+	})
+
+	result, err := Info(&client, "abcdef12345")
+	if err != nil {
+		t.Errorf("Info returned an error: %v", err)
+	}
+
+	expires, err := result.ExpiresAt()
+	if err != nil {
+		t.Errorf("Error extracting token expiration time: %v", err)
+	}
+
+	expected, _ := time.Parse(time.UnixDate, "Fri Aug 29 13:10:01 UTC 2014")
+	if expires != expected {
+		t.Errorf("Expected expiration time %s, but was %s", expected.Format(time.UnixDate), expires.Format(time.UnixDate))
+	}
+}
+
+func prepareAuthTokenHandler(t *testing.T, expectedMethod string, status int) gophercloud.ServiceClient {
+	client := gophercloud.ServiceClient{
+		Endpoint: endpoint(),
+		TokenID:  "12345abcdef",
+	}
+
+	mux.HandleFunc("/auth/tokens", func(w http.ResponseWriter, r *http.Request) {
+		testhelper.TestMethod(t, r, expectedMethod)
+		testhelper.TestHeader(t, r, "Content-Type", "application/json")
+		testhelper.TestHeader(t, r, "Accept", "application/json")
+		testhelper.TestHeader(t, r, "X-Auth-Token", "12345abcdef")
+		testhelper.TestHeader(t, r, "X-Subject-Token", "abcdef12345")
+
+		w.WriteHeader(status)
+	})
+
+	return client
+}
+
+func TestValidateRequestSuccessful(t *testing.T) {
+	setup()
+	defer teardown()
+	client := prepareAuthTokenHandler(t, "HEAD", http.StatusNoContent)
+
+	ok, err := Validate(&client, "abcdef12345")
+	if err != nil {
+		t.Errorf("Unexpected error from Validate: %v", err)
+	}
+
+	if !ok {
+		t.Errorf("Validate returned false for a valid token")
+	}
+}
+
+func TestValidateRequestFailure(t *testing.T) {
+	setup()
+	defer teardown()
+	client := prepareAuthTokenHandler(t, "HEAD", http.StatusNotFound)
+
+	ok, err := Validate(&client, "abcdef12345")
+	if err != nil {
+		t.Errorf("Unexpected error from Validate: %v", err)
+	}
+
+	if ok {
+		t.Errorf("Validate returned true for an invalid token")
+	}
+}
+
+func TestValidateRequestError(t *testing.T) {
+	setup()
+	defer teardown()
+	client := prepareAuthTokenHandler(t, "HEAD", http.StatusUnauthorized)
+
+	_, err := Validate(&client, "abcdef12345")
+	if err == nil {
+		t.Errorf("Missing expected error from Validate")
+	}
+}
+
+func TestRevokeRequestSuccessful(t *testing.T) {
+	setup()
+	defer teardown()
+	client := prepareAuthTokenHandler(t, "DELETE", http.StatusNoContent)
+
+	err := Revoke(&client, "abcdef12345")
+	if err != nil {
+		t.Errorf("Unexpected error from Revoke: %v", err)
+	}
+}
+
+func TestRevokeRequestError(t *testing.T) {
+	setup()
+	defer teardown()
+	client := prepareAuthTokenHandler(t, "DELETE", http.StatusNotFound)
+
+	err := Revoke(&client, "abcdef12345")
+	if err == nil {
+		t.Errorf("Missing expected error from Revoke")
+	}
+}
diff --git a/openstack/identity/v3/tokens/results.go b/openstack/identity/v3/tokens/results.go
index 9f0d623..8e0f018 100644
--- a/openstack/identity/v3/tokens/results.go
+++ b/openstack/identity/v3/tokens/results.go
@@ -1,5 +1,14 @@
 package tokens
 
+import (
+	"time"
+
+	"github.com/mitchellh/mapstructure"
+)
+
+// RFC3339Milli describes the time format used by identity API responses.
+const RFC3339Milli = "2006-01-02T15:04:05.999999Z"
+
 // TokenCreateResult contains the document structure returned from a Create call.
 type TokenCreateResult struct {
 	response map[string]interface{}