Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1151)

Unified Diff: pkg/oauth2/lib/src/client.dart

Issue 11420025: Add a package for authenticating via OAuth2. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Code review changes Created 8 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: pkg/oauth2/lib/src/client.dart
diff --git a/pkg/oauth2/lib/src/client.dart b/pkg/oauth2/lib/src/client.dart
new file mode 100644
index 0000000000000000000000000000000000000000..eabdd5d9bbdf6d0686c6e03703832fcc6efa4dd9
--- /dev/null
+++ b/pkg/oauth2/lib/src/client.dart
@@ -0,0 +1,125 @@
+// 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.
+
+library client;
+
+import 'dart:uri';
+
+import '../../../http/lib/http.dart' as http;
+
+import 'credentials.dart';
+import 'expiration_exception.dart';
+import 'utils.dart';
+
+// TODO(nweiz): Add an onCredentialsRefreshed event once we have some event
+// infrastructure.
+/// An OAuth2 client. This acts as a drop-in replacement for an
+/// [http.BaseClient], while sending OAuth2 authorization credentials along with
+/// each request.
+///
+/// The client also automatically refreshes its credentials if possible. When it
+/// makes a request, if its credentials are expired, it will first refresh them.
+/// This means that any request may throw an [AuthorizationException] if the
+/// refresh is not authorized for some reason, a [FormatException] if the
+/// authorization server provides ill-formatted responses, or an
+/// [ExpirationException] if the credentials are expired and can't be refreshed.
+///
+/// Currently this client doesn't attempt to identify errors from the resource
+/// server that are caused by authentication failure. However, it may throw
+/// [AuthorizationException]s for such errors in the future.
+///
+/// If you already have a set of [Credentials], you can construct a [Client]
+/// directly. However, in order to first obtain the credentials, you must
+/// authorize. At the time of writing, the only authorization method this
+/// library supports is [AuthorizationCodeGrant].
+class Client extends http.BaseClient {
+ /// The client identifier for this client. The authorization server will 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.
+ ///
+ /// This is usually global to the program using this library.
+ final String identifier;
+
+ /// The client secret for this client. The authorization server will 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.
+ ///
+ /// This is usually global to the program using this library.
+ ///
+ /// Note that clients whose source code or binary executable is readily
+ /// available may not be able to make sure the client secret is kept a secret.
+ /// This is fine; OAuth2 servers generally won't rely on knowing with
+ /// certainty that a client is who it claims to be.
+ final String secret;
+
+ /// The credentials this client uses to prove to the resource server that it's
+ /// authorized. This may change from request to request as the credentials
+ /// expire and the client refreshes them automatically.
+ Credentials get credentials => _credentials;
+ Credentials _credentials;
+
+ /// The underlying HTTP client.
+ final http.BaseClient _httpClient;
+
+ /// 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.
+ ///
+ /// [httpClient] is the underlying client that this forwards requests to after
+ /// adding authorization credentials to them.
+ Client(
+ this.identifier,
+ this.secret,
+ this._credentials,
+ {http.BaseClient httpClient})
+ : _httpClient = httpClient == null ? new http.Client() : httpClient;
+
+ /// Sends an HTTP request with OAuth2 authorization credentials attached. This
+ /// will also automatically refresh this client's [Credentials] before sending
+ /// the request if necessary.
+ Future<http.StreamedResponse> send(http.BaseRequest request) {
+ return async.chain((_) {
+ if (!credentials.isExpired) return new Future.immediate(null);
+ if (!credentials.canRefresh) throw new ExpirationException(credentials);
+ return refreshCredentials();
+ }).chain((_) {
+ request.headers['authorization'] = "Bearer ${credentials.accessToken}";
+ return _httpClient.send(request);
+ });
+ // TODO(nweiz): parse 401 errors that are caused by OAuth errors here.
+ }
+
+ /// Explicitly refreshes this client's credentials. Returns this client.
+ ///
+ /// This will throw a [StateError] if the [Credentials] can't be refreshed, an
+ /// [AuthorizationException] if refreshing the credentials fails, or a
+ /// [FormatError] if the authorization server returns invalid responses.
+ ///
+ /// You may request different scopes than the default by passing in
+ /// [newScopes]. These must be a subset of the scopes in the
+ /// [Credentials.scopes] field of [Client.credentials].
+ Future<Client> refreshCredentials([List<String> newScopes]) {
+ return async.chain((_) {
+ if (!credentials.canRefresh) {
+ var prefix = "OAuth credentials";
+ if (credentials.isExpired) prefix = "$prefix have expired and";
+ throw new StateError("$prefix can't be refreshed.");
+ }
+
+ return credentials.refresh(identifier, secret,
+ newScopes: newScopes, httpClient: _httpClient);
+ }).transform((credentials) {
+ _credentials = credentials;
+ return this;
+ });
+ }
+
+ /// Closes this client and its underlying HTTP client.
+ void close() {
+ if (_httpClient != null) _httpClient.close();
+ _httpClient = null;
+ }
+}

Powered by Google App Engine
This is Rietveld 408576698