Dart Documentationoauth2_clientClient

Client class

An OAuth2 client. This acts as a drop-in replacement for an http.Client, 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.

The client will also throw an AuthorizationException if the resource server returns a 401 response with a WWW-Authenticate header indicating that the current credentials are invalid.

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.
 http.Client _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.Client 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.then((_) {
     if (!credentials.isExpired) return new Future.value();
     if (!credentials.canRefresh) throw new ExpirationException(credentials);
     return refreshCredentials();
   }).then((_) {
     request.headers['authorization'] = "Bearer ${credentials.accessToken}";
     return _httpClient.send(request);
   }).then((response) {
     if (response.statusCode != 401 ||
         !response.headers.containsKey('www-authenticate')) {
       return response;
     }

     var authenticate;
     try {
       authenticate = new AuthenticateHeader.parse(
           response.headers['www-authenticate']);
     } on FormatException catch (e) {
       return response;
     }

     if (authenticate.scheme != 'bearer') return response;

     var params = authenticate.parameters;
     if (!params.containsKey('error')) return response;

     throw new AuthorizationException(
         params['error'], params['error_description'],
         params['error_uri'] == null ? null : Uri.parse(params['error_uri']));
   });
 }

 /// 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.then((_) {
     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);
   }).then((credentials) {
     _credentials = credentials;
     return this;
   });
 }

 /// Closes this client and its underlying HTTP client.
 void close() {
   if (_httpClient != null) _httpClient.close();
   _httpClient = null;
 }
}

Extends

BaseClient > Client

Constructors

new Client(String identifier, String secret, Credentials _credentials, {Client 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.Client httpClient})
 : _httpClient = httpClient == null ? new http.Client() : httpClient;

Properties

final Credentials credentials #

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;

final String identifier #

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

final String secret #

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

Methods

void close() #

Closes this client and its underlying HTTP client.

void close() {
 if (_httpClient != null) _httpClient.close();
 _httpClient = null;
}

Future<Response> delete(url, {Map<String, String> headers}) #

inherited from BaseClient

Sends an HTTP DELETE request with the given headers to the given URL, which can be a Uri or a String.

For more fine-grained control over the request, use send instead.

Future<Response> delete(url, {Map<String, String> headers}) =>
 _sendUnstreamed("DELETE", url, headers);

Future<Response> get(url, {Map<String, String> headers}) #

inherited from BaseClient

Sends an HTTP GET request with the given headers to the given URL, which can be a Uri or a String.

For more fine-grained control over the request, use send instead.

Future<Response> get(url, {Map<String, String> headers}) =>
 _sendUnstreamed("GET", url, headers);
inherited from BaseClient

Sends an HTTP HEAD request with the given headers to the given URL, which can be a Uri or a String.

For more fine-grained control over the request, use send instead.

Future<Response> head(url, {Map<String, String> headers}) =>
 _sendUnstreamed("HEAD", url, headers);

Future<Response> post(url, {Map<String, String> headers, Map<String, String> fields}) #

inherited from BaseClient

Sends an HTTP POST request with the given headers and fields to the given URL, which can be a Uri or a String. If any fields are specified, the content-type is automatically set to "application/x-www-form-urlencoded".

For more fine-grained control over the request, use send instead.

Future<Response> post(url,
   {Map<String, String> headers,
    Map<String, String> fields}) =>
 _sendUnstreamed("POST", url, headers, fields);

Future<Response> put(url, {Map<String, String> headers, Map<String, String> fields}) #

inherited from BaseClient

Sends an HTTP PUT request with the given headers and fields to the given URL, which can be a Uri or a String. If any fields are specified, the content-type is automatically set to "application/x-www-form-urlencoded".

For more fine-grained control over the request, use send instead.

Future<Response> put(url,
   {Map<String, String> headers,
    Map<String, String> fields}) =>
 _sendUnstreamed("PUT", url, headers, fields);

Future<String> read(url, {Map<String, String> headers}) #

inherited from BaseClient

Sends an HTTP GET request with the given headers to the given URL, which can be a Uri or a String, and returns a Future that completes to the body of the response as a String.

The Future will emit an HttpException if the response doesn't have a success status code.

For more fine-grained control over the request and response, use send or get instead.

Future<String> read(url, {Map<String, String> headers}) {
 return get(url, headers: headers).then((response) {
   _checkResponseSuccess(url, response);
   return response.body;
 });
}

Future<Uint8List> readBytes(url, {Map<String, String> headers}) #

inherited from BaseClient

Sends an HTTP GET request with the given headers to the given URL, which can be a Uri or a String, and returns a Future that completes to the body of the response as a list of bytes.

The Future will emit an HttpException if the response doesn't have a success status code.

For more fine-grained control over the request and response, use send or get instead.

Future<Uint8List> readBytes(url, {Map<String, String> headers}) {
 return get(url, headers: headers).then((response) {
   _checkResponseSuccess(url, response);
   return response.bodyBytes;
 });
}

Future<Client> refreshCredentials([List<String> newScopes]) #

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.then((_) {
   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);
 }).then((credentials) {
   _credentials = credentials;
   return this;
 });
}

Future<StreamedResponse> send(BaseRequest request) #

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.then((_) {
   if (!credentials.isExpired) return new Future.value();
   if (!credentials.canRefresh) throw new ExpirationException(credentials);
   return refreshCredentials();
 }).then((_) {
   request.headers['authorization'] = "Bearer ${credentials.accessToken}";
   return _httpClient.send(request);
 }).then((response) {
   if (response.statusCode != 401 ||
       !response.headers.containsKey('www-authenticate')) {
     return response;
   }

   var authenticate;
   try {
     authenticate = new AuthenticateHeader.parse(
         response.headers['www-authenticate']);
   } on FormatException catch (e) {
     return response;
   }

   if (authenticate.scheme != 'bearer') return response;

   var params = authenticate.parameters;
   if (!params.containsKey('error')) return response;

   throw new AuthorizationException(
       params['error'], params['error_description'],
       params['error_uri'] == null ? null : Uri.parse(params['error_uri']));
 });
}