Style changes.
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 686b6ac..f5865d2 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -23,6 +23,8 @@
 
 ## Non-breaking changes
 
+* Added a `resourceOwnerPasswordGrant` method.
+
 * The `scopes` argument to `AuthorizationCodeGrant.getAuthorizationUrl()` and
   `new Credentials()` and the `newScopes` argument to `Credentials.refresh` now
   take an `Iterable` rather than just a `List`.
diff --git a/README.md b/README.md
index ac6f501..ad3b0c0 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,3 @@
-# overview
 A client library for authenticating with a remote service via OAuth2 on
 behalf of a user, and making authorized HTTP requests with the user's OAuth2
 credentials.
@@ -15,14 +14,14 @@
 authorization. At the time of writing, this library only supports the
 [AuthorizationCodeGrant][] and [resourceOwnerPasswordGrant][] methods, but
 further methods may be added in the future. The following example uses this
-method to authenticate, and assumes that the library is being used by a server-side
-application.
+method to authenticate, and assumes that the library is being used by a
+server-side application.
 
 [AuthorizationCodeGrant]: http://www.dartdocs.org/documentation/oauth2/latest/index.html#oauth2/oauth2.AuthorizationCodeGrant
 [resourceOwnerPasswordGrant]: http://www.dartdocs.org/documentation/oauth2/latest/index.html#oauth2/oauth2.resourceOwnerPasswordGrant
 
-# examples
-## authorization code grant
+## Authorization Code Grant
+
 ```dart
 import 'dart:io'
 import 'package:oauth2/oauth2.dart' as oauth2;
@@ -112,14 +111,41 @@
   print(result);
 }
 ```
-## resource owner password grant
 
-```
-    // Get a fully authorized client
-   var client = await oauth2.resourceOwnerPasswordGrant(
-          authorizationEndpoint, 'username', 'userpass',
-          clientId: 'client', clientSecret: 'secret');
-   // Interact with server using the authorized client
-   var result =  client.read("http://example.com/protected-resources.txt");
+## Resource Owner Password Grant
 
+```dart
+// This URL is an endpoint that's provided by the authorization server. It's
+// usually included in the server's documentation of its OAuth2 API.
+final authorizationEndpoint =
+    Uri.parse("http://example.com/oauth2/authorization");
+
+// The user should supply their own username and password.
+final username = "example user";
+final password = "example password";
+
+// The authorization server may issue each client a separate client
+// identifier and secret, which allows the server to tell which client
+// is accessing it. Some servers may also have an anonymous
+// identifier/secret pair that any client may use.
+//
+// Some servers don't require the client to authenticate itself, in which case
+// these should be omitted.
+final identifier = "my client identifier";
+final secret = "my client secret";
+
+// Make a request to the authorization endpoint that will produce the fully
+// authenticated Client.
+var client = await oauth2.resourceOwnerPasswordGrant(
+    authorizationEndpoint, username, password,
+    identifier: identifier, secret: secret);
+
+// Once you have the client, you can use it just like any other HTTP client.
+var result = await client.read("http://example.com/protected-resources.txt");
+
+// Once we're done with the client, save the credentials file. This will allow
+// us to re-use the credentials and avoid storing the username and password
+// directly.
+new File("~/.myapp/credentials.json")
+    .writeAsString(client.credentials.toJson());
 ```
diff --git a/lib/src/client.dart b/lib/src/client.dart
index adf53d5..c27ab4e 100644
--- a/lib/src/client.dart
+++ b/lib/src/client.dart
@@ -12,7 +12,6 @@
 import 'authorization_exception.dart';
 import 'credentials.dart';
 import 'expiration_exception.dart';
-import 'utils.dart';
 
 // TODO(nweiz): Add an onCredentialsRefreshed event once we have some event
 // infrastructure.
@@ -79,7 +78,8 @@
   /// Creates a new client from a pre-existing set of credentials.
   ///
   /// When authorizing a client for the first time, you should use
-  /// [AuthorizationCodeGrant] instead of constructing a [Client] directly.
+  /// [AuthorizationCodeGrant] or [resourceOwnerPasswordGrant] instead of
+  /// constructing a [Client] directly.
   ///
   /// [httpClient] is the underlying client that this forwards requests to after
   /// adding authorization credentials to them.
diff --git a/lib/src/resource_owner_password_grant.dart b/lib/src/resource_owner_password_grant.dart
index 3d06a6d..28498ca 100644
--- a/lib/src/resource_owner_password_grant.dart
+++ b/lib/src/resource_owner_password_grant.dart
@@ -2,61 +2,69 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-library resource_owner_password_grant;
+library oauth2.resource_owner_password_grant;
 
 import 'dart:async';
-import 'dart:convert';
+
 import 'package:http/http.dart' as http;
-import 'package:crypto/crypto.dart';
+
 import 'client.dart';
 import 'handle_access_token_response.dart';
 import 'utils.dart';
 
-/// Implementation of the [resource owner password grant] (http://tools.ietf.org/html/draft-ietf-oauth-v2-31#section-4.3) for oauth 2.
+/// Obtains credentials using a [resource owner password grant][].
 ///
-
-/// Returns a fully-authorized [Client] if authorization is successful.
+/// This mode of authorization uses the user's username and password to obtain
+/// an authentication token, which can then be stored. This is safer than
+/// storing the username and password directly, but it should be avoided if any
+/// other authorization method is available, since it requires the user to
+/// provide their username and password to a third party (you).
 ///
-/// The client can provide a [clientId] and [clientSecret] for authenticating itself  as required by the server. The
-/// default authentication is basic authentication as recommended by the spec. This can be overridden to be passed as
-/// query parameters by passing [useBasicAuth]: false.
+/// The client [identifier] and [secret] may be issued by the server, and are
+/// used to identify and authenticate your specific OAuth2 client. These are
+/// usually global to the program using this library.
 ///
-/// Specific scopes can be requested vis [scopes], but is not required.  The server may choose to grant less scopes than
-/// actually requested.  The actual scopes granted are returned in [Credentials] property of the [Client].
-///
+/// The specific permissions being requested from the authorization server may
+/// be specified via [scopes]. The scope strings are specific to the
+/// authorization server and may be found in its documentation. Note that you
+/// may not be granted access to every scope you request; you may check the
+/// [Credentials.scopes] field of [Client.credentials] to see which scopes you
+/// were granted.
 Future<Client> resourceOwnerPasswordGrant(
-    Uri authorizationEndpoint, String username, String password,
-    {String clientId,
-    String clientSecret,
-    List<String> scopes: const [],
-    bool useBasicAuth: true,
+    Uri authorizationEndpoint,
+    String username,
+    String password,
+    {String identifier,
+    String secret,
+    Iterable<String> scopes,
+    bool basicAuth: true,
     http.Client httpClient}) async {
-
   var startTime = new DateTime.now();
 
-  var body = {"grant_type": "password", "username": username, "password": password};
+  var body = {
+    "grant_type": "password",
+    "username": username,
+    "password": password
+  };
 
   var headers = {};
 
-  if (clientId != null) {
-    if (useBasicAuth) {
-      headers['authorization'] = 'Basic ' +
-          CryptoUtils.bytesToBase64(UTF8.encode('$clientId:$clientSecret'));
+  if (identifier != null) {
+    if (basicAuth) {
+      headers['Authorization'] = basicAuthHeader(identifier, secret);
     } else {
-      body['client_id'] = clientId;
-      if(clientSecret != null) body['client_secret'] = clientSecret;
+      body['client_id'] = identifier;
+      if (secret != null) body['client_secret'] = secret;
     }
   }
 
-  if (!scopes.isEmpty) body['scope'] = scopes.join(' ');
+  if (scopes != null && !scopes.isEmpty) body['scope'] = scopes.join(' ');
 
-  if (httpClient == null) {
-    httpClient = new http.Client();
-  }
-
-  var response = await httpClient.post(authorizationEndpoint, headers: headers, body: body);
+  if (httpClient == null) httpClient = new http.Client();
+  var response = await httpClient.post(authorizationEndpoint,
+      headers: headers, body: body);
 
   var credentials = await handleAccessTokenResponse(
       response, authorizationEndpoint, startTime, scopes);
-  return new Client(credentials, identifier: clientId, secret: clientSecret);
+  return new Client(credentials, identifier: identifier, secret: secret);
 }
diff --git a/pubspec.yaml b/pubspec.yaml
index f52b8be..bd6bd4c 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -1,5 +1,5 @@
 name: oauth2
-version: 1.0.0-dev
+version: 1.0.0
 author: Dart Team <misc@dartlang.org>
 homepage: http://github.com/dart-lang/oauth2
 description: >
diff --git a/test/resource_owner_password_grant_test.dart b/test/resource_owner_password_grant_test.dart
index dc4631f..1d73a0f 100644
--- a/test/resource_owner_password_grant_test.dart
+++ b/test/resource_owner_password_grant_test.dart
@@ -1,45 +1,48 @@
 // Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
+
 @TestOn("vm")
-library resource_owner_password_grant_test;
 
-import 'dart:convert';
 import 'dart:async';
-import 'package:http/http.dart' as http;
-import 'package:crypto/crypto.dart';
+import 'dart:convert';
 
-import 'package:test/test.dart';
+import 'package:crypto/crypto.dart';
+import 'package:http/http.dart' as http;
 import 'package:oauth2/oauth2.dart' as oauth2;
+import 'package:test/test.dart';
+
 import 'utils.dart';
 
-final String SUCCESS = JSON.encode({
+final success = JSON.encode({
   "access_token": "2YotnFZFEjr1zCsicMWpAA",
   "token_type": "bearer",
   "expires_in": 3600,
   "refresh_token": "tGzv3JOkF0XG5Qx2TlKWIA",
 });
 
-var auth = 'Basic ${CryptoUtils.bytesToBase64(UTF8.encode('client:secret'))}';
+var auth = 'Basic Y2xpZW50OnNlY3JldA==';
 var authEndpoint = Uri.parse('https://example.com');
-var expectClient = new ExpectClient();
 
 void main() {
+  var expectClient;
+  setUp(() => expectClient = new ExpectClient());
+
   group('basic', () {
     test('builds correct request with client when using basic auth for client',
         () async {
-      expectClient.expectRequest((request) {
+      expectClient.expectRequest((request) async {
         expect(auth, equals(request.headers['authorization']));
         expect(request.bodyFields['grant_type'], equals('password'));
         expect(request.bodyFields['username'], equals('username'));
         expect(request.bodyFields['password'], equals('userpass'));
-        return new Future.value(new http.Response(SUCCESS, 200,
-            headers: {'content-type': 'application/json'}));
+        return new http.Response(success, 200,
+            headers: {'content-type': 'application/json'});
       });
 
       var client = await oauth2.resourceOwnerPasswordGrant(
           authEndpoint, 'username', 'userpass',
-          clientId: 'client', clientSecret: 'secret', httpClient: expectClient);
+          identifier: 'client', secret: 'secret', httpClient: expectClient);
 
       expect(client.credentials, isNotNull);
       expect(client.credentials.accessToken, equals('2YotnFZFEjr1zCsicMWpAA'));
@@ -47,34 +50,34 @@
 
     test('builds correct request when using query parameters for client',
         () async {
-      expectClient.expectRequest((request) {
+      expectClient.expectRequest((request) async {
         expect(request.bodyFields['grant_type'], equals('password'));
         expect(request.bodyFields['client_id'], equals('client'));
         expect(request.bodyFields['client_secret'], equals('secret'));
         expect(request.bodyFields['username'], equals('username'));
         expect(request.bodyFields['password'], equals('userpass'));
-        return new Future.value(new http.Response(SUCCESS, 200,
-            headers: {'content-type': 'application/json'}));
+        return new http.Response(success, 200,
+            headers: {'content-type': 'application/json'});
       });
 
       var client = await oauth2.resourceOwnerPasswordGrant(
           authEndpoint, 'username', 'userpass',
-          clientId: 'client',
-          clientSecret: 'secret',
-          useBasicAuth: false,
+          identifier: 'client',
+          secret: 'secret',
+          basicAuth: false,
           httpClient: expectClient);
       expect(client.credentials, isNotNull);
       expect(client.credentials.accessToken, equals('2YotnFZFEjr1zCsicMWpAA'));
     });
 
     test('builds correct request using scope', () async {
-      expectClient.expectRequest((request) {
+      expectClient.expectRequest((request) async {
         expect(request.bodyFields['grant_type'], equals('password'));
         expect(request.bodyFields['username'], equals('username'));
         expect(request.bodyFields['password'], equals('userpass'));
         expect(request.bodyFields['scope'], equals('one two'));
-        return new Future.value(new http.Response(SUCCESS, 200,
-            headers: {'content-type': 'application/json'}));
+        return new http.Response(success, 200,
+            headers: {'content-type': 'application/json'});
       });
 
       var client = await oauth2.resourceOwnerPasswordGrant(
@@ -87,22 +90,22 @@
     test('merges with existing query parameters', () async {
       var authEndpoint = Uri.parse('https://example.com?query=value');
 
-      expectClient.expectRequest((request) {
+      expectClient.expectRequest((request) async {
         expect(request.bodyFields['grant_type'], equals('password'));
         expect(request.bodyFields['client_id'], equals('client'));
         expect(request.bodyFields['client_secret'], equals('secret'));
         expect(request.bodyFields['username'], equals('username'));
         expect(request.bodyFields['password'], equals('userpass'));
         expect(request.url.queryParameters['query'], equals('value'));
-        return new Future.value(new http.Response(SUCCESS, 200,
-            headers: {'content-type': 'application/json'}));
+        return new http.Response(success, 200,
+            headers: {'content-type': 'application/json'});
       });
 
       var client = await oauth2.resourceOwnerPasswordGrant(
           authEndpoint, 'username', 'userpass',
-          clientId: 'client',
-          clientSecret: 'secret',
-          useBasicAuth: false,
+          identifier: 'client',
+          secret: 'secret',
+          basicAuth: false,
           httpClient: expectClient);
       expect(client.credentials, isNotNull);
       expect(client.credentials.accessToken, equals('2YotnFZFEjr1zCsicMWpAA'));