Authentication at the identity client level.
diff --git a/openstack/identity/v3/client.go b/openstack/identity/v3/client.go
index 8c6e3e4..5f25ee6 100644
--- a/openstack/identity/v3/client.go
+++ b/openstack/identity/v3/client.go
@@ -4,11 +4,14 @@
 	"time"
 
 	"github.com/rackspace/gophercloud"
+	"github.com/rackspace/gophercloud/openstack/identity/v3/tokens"
 )
 
 // Client abstracts the connection information necessary to make API calls to Identity v3 resources.
 // It exists mainly to adhere to the IdentityService interface.
-type Client gophercloud.ServiceClient
+type Client struct {
+	gophercloud.ServiceClient
+}
 
 // Token models a token acquired from the tokens/ API resource.
 type Token struct {
@@ -19,12 +22,34 @@
 // NewClient creates a new client associated with the v3 identity service of a provider.
 func NewClient(provider *gophercloud.ProviderClient) *Client {
 	return &Client{
-		ProviderClient: *provider,
-		Endpoint:       provider.IdentityEndpoint + "v3/",
+		ServiceClient: gophercloud.ServiceClient{
+			ProviderClient: *provider,
+			Endpoint:       provider.IdentityEndpoint + "v3/",
+		},
 	}
 }
 
 // Authenticate provides the supplied credentials to an identity v3 endpoint and attempts to acquire a token.
 func (c *Client) Authenticate(authOptions gophercloud.AuthOptions) (*Token, error) {
-	return nil, nil
+	c.ServiceClient.ProviderClient.Options = authOptions
+
+	result, err := tokens.Create(&c.ServiceClient, nil)
+	if err != nil {
+		return nil, err
+	}
+
+	tokenID, err := result.TokenID()
+	if err != nil {
+		return nil, err
+	}
+
+	expiresAt, err := result.ExpiresAt()
+	if err != nil {
+		return nil, err
+	}
+
+	return &Token{
+		ID:        tokenID,
+		ExpiresAt: expiresAt,
+	}, nil
 }