├── .gitignore ├── .travis.yml ├── LICENSE ├── README.md ├── lib ├── oauth1.dart └── src │ ├── authorization.dart │ ├── authorization_header.dart │ ├── authorization_header_builder.dart │ ├── authorization_response.dart │ ├── client.dart │ ├── client_credentials.dart │ ├── credentials.dart │ ├── platform.dart │ └── signature_method.dart ├── pubspec.yaml └── test └── authorization_test.dart /.gitignore: -------------------------------------------------------------------------------- 1 | # Stealed from https://github.com/github/gitignore/blob/master/Dart.gitignore 2 | # Don’t commit the following directories created by pub. 3 | build/ 4 | packages/ 5 | 6 | 7 | # Or the files created by dart2js. 8 | *.dart.js 9 | *.dart.precompiled.js 10 | *.js_ 11 | *.js.deps 12 | *.js.map 13 | 14 | 15 | # Include when developing application packages. 16 | pubspec.lock 17 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: dart 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2014, kumar8600 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright notice, 8 | this list of conditions and the following disclaimer. 9 | * Redistributions in binary form must reproduce the above copyright 10 | notice, this list of conditions and the following disclaimer in the 11 | documentation and/or other materials provided with the distribution. 12 | * Neither the name of kumar8600 nor the names of its contributors may be 13 | used to endorse or promote products derived from this software without 14 | specific prior written permission. 15 | 16 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 | ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 20 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 | POSSIBILITY OF SUCH DAMAGE. 27 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | dart-oauth1 2 | =========== 3 | 4 | [![Build Status](https://travis-ci.org/kumar8600/dart-oauth1.svg?branch=master)](https://travis-ci.org/kumar8600/dart-oauth1) 5 | 6 | "[RFC 5849: The OAuth 1.0 Protocol][rfc5849]" client implementation for dart 7 | 8 | Usage 9 | ----- 10 | 11 | Add to `pubspec.yaml`: 12 | 13 | ```yaml 14 | dependencies: 15 | oauth1: 16 | git: git://github.com/kumar8600/dart-oauth1.git 17 | ``` 18 | 19 | Please use like below. 20 | 21 | ```dart 22 | import 'dart:io'; 23 | import 'package:oauth1/oauth1.dart' as oauth1; 24 | 25 | void main() { 26 | // define platform (server) 27 | var platform = new oauth1.Platform( 28 | 'https://api.twitter.com/oauth/request_token', // temporary credentials request 29 | 'https://api.twitter.com/oauth/authorize', // resource owner authorization 30 | 'https://api.twitter.com/oauth/access_token', // token credentials request 31 | oauth1.SignatureMethods.HMAC_SHA1 // signature method 32 | ); 33 | 34 | // define client credentials (consumer keys) 35 | const String apiKey = 'LLDeVY0ySvjoOVmJ2XgBItvTV'; 36 | const String apiSecret = 'JmEpkWXXmY7BYoQor5AyR84BD2BiN47GIBUPXn3bopZqodJ0MV'; 37 | var clientCredentials = new oauth1.ClientCredentials(apiKey, apiSecret); 38 | 39 | // create Authorization object with client credentials and platform definition 40 | var auth = new oauth1.Authorization(clientCredentials, platform); 41 | 42 | // request temporary credentials (request tokens) 43 | auth.requestTemporaryCredentials('oob').then((res) { 44 | // redirect to authorization page 45 | print("Open with your browser: ${auth.getResourceOwnerAuthorizationURI(res.credentials.token)}"); 46 | 47 | // get verifier (PIN) 48 | stdout.write("PIN: "); 49 | String verifier = stdin.readLineSync(); 50 | 51 | // request token credentials (access tokens) 52 | return auth.requestTokenCredentials(res.credentials, verifier); 53 | }).then((res) { 54 | // yeah, you got token credentials 55 | // create Client object 56 | var client = new oauth1.Client(platform.signatureMethod, clientCredentials, res.credentials); 57 | 58 | // now you can access to protected resources via client 59 | client.get('https://api.twitter.com/1.1/statuses/home_timeline.json?count=1').then((res) { 60 | print(res.body); 61 | }); 62 | 63 | // NOTE: you can get optional values from AuthorizationResponse object 64 | print("Your screen name is " + res.optionalParameters['screen_name']); 65 | }); 66 | } 67 | 68 | ``` 69 | 70 | In addition, You should save and load the granted token credentials from your drive. Of cource, you don't need to authorize when you did it. 71 | 72 | [rfc5849]: http://tools.ietf.org/html/rfc5849 73 | -------------------------------------------------------------------------------- /lib/oauth1.dart: -------------------------------------------------------------------------------- 1 | library oauth1; 2 | 3 | export 'src/client_credentials.dart'; 4 | export 'src/credentials.dart'; 5 | export 'src/signature_method.dart'; 6 | export 'src/client.dart'; 7 | export 'src/authorization.dart'; 8 | export 'src/platform.dart'; 9 | -------------------------------------------------------------------------------- /lib/src/authorization.dart: -------------------------------------------------------------------------------- 1 | library authorization; 2 | 3 | import 'dart:async'; 4 | import 'package:http/http.dart' as http; 5 | import 'package:formler/formler.dart'; 6 | 7 | import 'credentials.dart'; 8 | import 'client_credentials.dart'; 9 | import 'platform.dart'; 10 | import 'authorization_header_builder.dart'; 11 | import 'authorization_response.dart'; 12 | 13 | /** 14 | * A proxy class describing OAuth 1.0 redirection-based authorization. 15 | * http://tools.ietf.org/html/rfc5849#section-2 16 | * 17 | * Redirection works are responded to client. 18 | * So you can do PIN-based authorization too if you want. 19 | */ 20 | class Authorization { 21 | final ClientCredentials _clientCredentials; 22 | final Platform _platform; 23 | final http.BaseClient _httpClient; 24 | 25 | /** 26 | * A constructor of Authorization. 27 | * 28 | * If you want to use in web browser, pass http.BrowserClient object for httpClient. 29 | * https://api.dartlang.org/apidocs/channels/stable/dartdoc-viewer/http/http-browser_client.BrowserClient 30 | */ 31 | Authorization(this._clientCredentials, this._platform, [http.BaseClient httpClient]) : 32 | _httpClient = httpClient != null ? httpClient : new http.Client(); 33 | 34 | /** 35 | * Obtain a set of temporary credentials from the server. 36 | * http://tools.ietf.org/html/rfc5849#section-2.1 37 | * 38 | * If not callbackURI passed, authentication becomes PIN-based. 39 | */ 40 | Future requestTemporaryCredentials([String callbackURI]) { 41 | if (callbackURI == null) { 42 | callbackURI = 'oob'; 43 | } 44 | Map additionalParams = { 45 | 'oauth_callback': callbackURI 46 | }; 47 | var ahb = new AuthorizationHeaderBuilder(); 48 | ahb.signatureMethod = _platform.signatureMethod; 49 | ahb.clientCredentials = _clientCredentials; 50 | ahb.method = 'POST'; 51 | ahb.url = _platform.temporaryCredentialsRequestURI; 52 | ahb.additionalParameters = additionalParams; 53 | 54 | return _httpClient.post(_platform.temporaryCredentialsRequestURI, headers: { 55 | 'Authorization': ahb.build().toString() 56 | }).then((res) { 57 | if ((res as http.Response).statusCode != 200) { 58 | throw new StateError(res.body); 59 | } 60 | Map params = Formler.parseUrlEncoded(res.body); 61 | if (params['oauth_callback_confirmed'].toLowerCase() != 'true') { 62 | throw new StateError("oauth_callback_confirmed must be true"); 63 | } 64 | return new AuthorizationResponse.fromMap(params); 65 | }); 66 | } 67 | 68 | /** 69 | * Get resource owner authorization URI. 70 | * http://tools.ietf.org/html/rfc5849#section-2.2 71 | */ 72 | String getResourceOwnerAuthorizationURI(String temporaryCredentialsIdentifier) { 73 | return _platform.resourceOwnerAuthorizationURI + "?oauth_token=" + Uri.encodeComponent(temporaryCredentialsIdentifier); 74 | } 75 | 76 | /** 77 | * Obtain a set of token credentials from the server. 78 | * http://tools.ietf.org/html/rfc5849#section-2.3 79 | */ 80 | Future requestTokenCredentials(Credentials tokenCredentials, String verifier) { 81 | Map additionalParams = { 82 | 'oauth_verifier': verifier 83 | }; 84 | var ahb = new AuthorizationHeaderBuilder(); 85 | ahb.signatureMethod = _platform.signatureMethod; 86 | ahb.clientCredentials = _clientCredentials; 87 | ahb.credentials = tokenCredentials; 88 | ahb.method = 'POST'; 89 | ahb.url = _platform.tokenCredentialsRequestURI; 90 | ahb.additionalParameters = additionalParams; 91 | 92 | return _httpClient.post(_platform.tokenCredentialsRequestURI, headers: { 93 | 'Authorization': ahb.build().toString() 94 | }).then((res) { 95 | if ((res as http.Response).statusCode != 200) { 96 | throw new StateError(res.body); 97 | } 98 | Map params = Formler.parseUrlEncoded(res.body); 99 | return new AuthorizationResponse.fromMap(params); 100 | }); 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /lib/src/authorization_header.dart: -------------------------------------------------------------------------------- 1 | library authorization_header; 2 | 3 | import 'package:uuid/uuid.dart'; 4 | 5 | import 'signature_method.dart'; 6 | import 'client_credentials.dart'; 7 | import 'credentials.dart'; 8 | 9 | /** 10 | * A class describing Authorization Header. 11 | * http://tools.ietf.org/html/rfc5849#section-3.5.1 12 | */ 13 | class AuthorizationHeader { 14 | final SignatureMethod _signatureMethod; 15 | final ClientCredentials _clientCredentials; 16 | final Credentials _credentials; 17 | final String _method; 18 | final String _url; 19 | final Map _additionalParameters; 20 | 21 | static final _uuid = new Uuid(); 22 | 23 | AuthorizationHeader(this._signatureMethod, this._clientCredentials, this._credentials, this._method, this._url, this._additionalParameters); 24 | 25 | /** 26 | * Set Authorization header to request. 27 | * 28 | * Below parameters are provided default values: 29 | * - oauth_signature_method 30 | * - oauth_signature 31 | * - oauth_timestamp 32 | * - oauth_nonce 33 | * - oauth_version 34 | * - oauth_consumer_key 35 | * - oauth_token 36 | * - oauth_token_secret 37 | * 38 | * You can add parameters by _authorizationHeader. 39 | * (You can override too but I don't recommend.) 40 | */ 41 | @override 42 | String toString() { 43 | Map params = new Map(); 44 | 45 | params['oauth_nonce'] = new DateTime.now().millisecondsSinceEpoch.toString(); 46 | params['oauth_signature_method'] = _signatureMethod.name; 47 | params['oauth_timestamp'] = (new DateTime.now().millisecondsSinceEpoch / 1000).floor().toString(); 48 | params['oauth_consumer_key'] = _clientCredentials.token; 49 | params['oauth_version'] = '1.0'; 50 | if (_credentials != null) { 51 | params['oauth_token'] = _credentials.token; 52 | } 53 | params.addAll(_additionalParameters); 54 | if (!params.containsKey('oauth_signature')) { 55 | params['oauth_signature'] = _createSignature(_method, _url, params); 56 | } 57 | 58 | String authHeader = 'OAuth ' + params.keys.map((k) { 59 | return '$k="${Uri.encodeComponent(params[k])}"'; 60 | }).join(', '); 61 | return authHeader; 62 | } 63 | 64 | /** 65 | * Create signature in ways referred from 66 | * https://dev.twitter.com/docs/auth/creating-signature. 67 | */ 68 | String _createSignature(String method, String url, Map params) { 69 | // Referred from https://dev.twitter.com/docs/auth/creating-signature 70 | if (params.isEmpty) { 71 | throw new ArgumentError("params is empty."); 72 | } 73 | Uri uri = Uri.parse(url); 74 | 75 | // 76 | // Collecting parameters 77 | // 78 | 79 | // 1. Percent encode every key and value 80 | // that will be signed. 81 | Map encodedParams = new Map(); 82 | params.forEach((k, v) { 83 | encodedParams[Uri.encodeComponent(k)] = Uri.encodeComponent(v); 84 | }); 85 | uri.queryParameters.forEach((k, v) { 86 | encodedParams[Uri.encodeComponent(k)] = Uri.encodeComponent(v); 87 | }); 88 | params.remove("realm"); 89 | 90 | // 2. Sort the list of parameters alphabetically[1] 91 | // by encoded key[2]. 92 | List sortedEncodedKeys = encodedParams.keys.toList()..sort(); 93 | 94 | // 3. For each key/value pair: 95 | // 4. Append the encoded key to the output string. 96 | // 5. Append the '=' character to the output string. 97 | // 6. Append the encoded value to the output string. 98 | // 7. If there are more key/value pairs remaining, 99 | // append a '&' character to the output string. 100 | String baseParams = sortedEncodedKeys.map((k) { 101 | return '$k=${encodedParams[k]}'; 102 | }).join('&'); 103 | 104 | // 105 | // Creating the signature base string 106 | // 107 | 108 | StringBuffer base = new StringBuffer(); 109 | // 1. Convert the HTTP Method to uppercase and set the 110 | // output string equal to this value. 111 | base.write(method.toUpperCase()); 112 | 113 | // 2. Append the '&' character to the output string. 114 | base.write('&'); 115 | 116 | // 3. Percent encode the URL origin and path, and append it to the 117 | // output string. 118 | base.write(Uri.encodeComponent(uri.origin + uri.path)); 119 | 120 | // 4. Append the '&' character to the output string. 121 | base.write('&'); 122 | 123 | // 5. Percent encode the parameter string and append it 124 | // to the output string. 125 | base.write(Uri.encodeComponent(baseParams.toString())); 126 | 127 | // 128 | // Getting a signing key 129 | // 130 | 131 | // The signing key is simply the percent encoded consumer 132 | // secret, followed by an ampersand character '&', 133 | // followed by the percent encoded token secret: 134 | String consumerSecret = Uri.encodeComponent(_clientCredentials.tokenSecret); 135 | String tokenSecret = _credentials != null ? Uri.encodeComponent(_credentials.tokenSecret) : ""; 136 | String signingKey = "$consumerSecret&$tokenSecret"; 137 | 138 | // 139 | // Calculating the signature 140 | // 141 | return _signatureMethod.sign(signingKey, base.toString()); 142 | } 143 | 144 | } 145 | -------------------------------------------------------------------------------- /lib/src/authorization_header_builder.dart: -------------------------------------------------------------------------------- 1 | library auhthorization_header_builder; 2 | 3 | import 'authorization_header.dart'; 4 | import 'signature_method.dart'; 5 | import 'client_credentials.dart'; 6 | import 'credentials.dart'; 7 | 8 | /** 9 | * A builder class for AuthorizationHeader. 10 | */ 11 | class AuthorizationHeaderBuilder { 12 | SignatureMethod _signatureMethod; 13 | ClientCredentials _clientCredentials; 14 | Credentials _credentials; 15 | String _method; 16 | String _url; 17 | Map _additionalParameters; 18 | 19 | AuthorizationHeaderBuilder(); 20 | AuthorizationHeaderBuilder.from(AuthorizationHeaderBuilder other) : 21 | _signatureMethod = other._signatureMethod, 22 | _clientCredentials = other._clientCredentials, 23 | _credentials = other._credentials, 24 | _method = other._method, 25 | _url = other._url, 26 | _additionalParameters = other._additionalParameters; 27 | 28 | set signatureMethod(SignatureMethod value) => _signatureMethod = value; 29 | set clientCredentials(ClientCredentials value) => _clientCredentials = value; 30 | set credentials(Credentials value) => _credentials = value; 31 | set method(String value) => _method = value; 32 | set url(String value) => _url = value; 33 | set additionalParameters(Map value) => _additionalParameters = value; 34 | 35 | AuthorizationHeader build() { 36 | if (_signatureMethod == null) { 37 | throw new StateError("signatureMethod is not set"); 38 | } 39 | if (_clientCredentials == null) { 40 | throw new StateError("clientCredentials is not set"); 41 | } 42 | if (_method == null) { 43 | throw new StateError("method is not set"); 44 | } 45 | if (_url == null) { 46 | throw new StateError("url is not set"); 47 | } 48 | return new AuthorizationHeader(_signatureMethod, _clientCredentials, _credentials, _method, _url, _additionalParameters); 49 | } 50 | } -------------------------------------------------------------------------------- /lib/src/authorization_response.dart: -------------------------------------------------------------------------------- 1 | library authorization_response; 2 | 3 | import 'credentials.dart'; 4 | 5 | /// A class describing Response of Authoriazation request. 6 | class AuthorizationResponse { 7 | final Credentials _credentials; 8 | final Map _optionalParameters; 9 | 10 | AuthorizationResponse(this._credentials, this._optionalParameters); 11 | factory AuthorizationResponse.fromMap(Map parameters) { 12 | Map paramsCopy = new Map.from(parameters); 13 | Credentials cred = new Credentials.fromMap(paramsCopy); 14 | paramsCopy.remove('oauth_token'); 15 | paramsCopy.remove('oauth_token_secret'); 16 | return new AuthorizationResponse(cred, paramsCopy); 17 | } 18 | 19 | Credentials get credentials => _credentials; 20 | Map get optionalParameters => _optionalParameters; 21 | } -------------------------------------------------------------------------------- /lib/src/client.dart: -------------------------------------------------------------------------------- 1 | library oauth1_client; 2 | 3 | import 'dart:async'; 4 | import 'package:http/http.dart' as http; 5 | import 'package:formler/formler.dart'; 6 | 7 | import 'signature_method.dart'; 8 | import 'client_credentials.dart'; 9 | import 'credentials.dart'; 10 | import 'authorization_header_builder.dart'; 11 | 12 | /** 13 | * A proxy class describing OAuth 1.0 Authenticated Request 14 | * http://tools.ietf.org/html/rfc5849#section-3 15 | * 16 | * If _credentials is null, this is usable for authorization requests too. 17 | */ 18 | class Client extends http.BaseClient { 19 | final SignatureMethod _signatureMethod; 20 | final ClientCredentials _clientCredentials; 21 | final Credentials _credentials; 22 | final http.BaseClient _httpClient; 23 | 24 | /** 25 | * A constructor of Client. 26 | * 27 | * If you want to use in web browser, pass http.BrowserClient object for httpClient. 28 | * https://api.dartlang.org/apidocs/channels/stable/dartdoc-viewer/http/http-browser_client.BrowserClient 29 | */ 30 | Client(this._signatureMethod, this._clientCredentials, this._credentials, [http.BaseClient httpClient]) : 31 | _httpClient = httpClient != null ? httpClient : new http.Client(); 32 | 33 | @override 34 | Future send(http.BaseRequest request) { 35 | var ahb = new AuthorizationHeaderBuilder(); 36 | ahb.signatureMethod = _signatureMethod; 37 | ahb.clientCredentials = _clientCredentials; 38 | ahb.credentials = _credentials; 39 | ahb.method = request.method; 40 | ahb.url = request.url.toString(); 41 | var headers = request.headers; 42 | Map additionalParameters = new Map(); 43 | if (headers.containsKey('Authorization')) { 44 | additionalParameters = Formler.parseUrlEncoded(headers['Authorization']); 45 | } 46 | if (headers.containsKey('content-type') && 47 | headers['content-type'].contains('application/x-www-form-urlencoded') && 48 | (request as http.Request).body != null) { 49 | additionalParameters.addAll(Formler.parseUrlEncoded((request as http.Request).body)); 50 | } 51 | ahb.additionalParameters = additionalParameters; 52 | 53 | request.headers['Authorization'] = ahb.build().toString(); 54 | return _httpClient.send(request); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /lib/src/client_credentials.dart: -------------------------------------------------------------------------------- 1 | library client_credentials; 2 | 3 | /** 4 | * A class describing OAuth client credentials. 5 | */ 6 | class ClientCredentials { 7 | final String _token; 8 | final String _tokenSecret; 9 | 10 | ClientCredentials(this._token, this._tokenSecret); 11 | 12 | String get token => _token; 13 | String get tokenSecret => _tokenSecret; 14 | } 15 | -------------------------------------------------------------------------------- /lib/src/credentials.dart: -------------------------------------------------------------------------------- 1 | library credentials; 2 | 3 | import 'dart:convert'; 4 | 5 | /** 6 | * A class describing OAuth credentials except for client credential 7 | */ 8 | class Credentials { 9 | final String _token; 10 | final String _tokenSecret; 11 | 12 | Credentials(this._token, this._tokenSecret); 13 | factory Credentials.fromMap(Map parameters) { 14 | if (!parameters.containsKey('oauth_token')) { 15 | throw new ArgumentError("params doesn't have a key 'oauth_token'"); 16 | } 17 | if (!parameters.containsKey('oauth_token_secret')) { 18 | throw new ArgumentError("params doesn't have a key 'oauth_token_secret'"); 19 | } 20 | return new Credentials(parameters['oauth_token'], parameters['oauth_token_secret']); 21 | } 22 | factory Credentials.fromJSON(String json) { 23 | return new Credentials.fromMap(JSON.decode(json)); 24 | } 25 | 26 | String get token => _token; 27 | String get tokenSecret => _tokenSecret; 28 | 29 | String toString() { 30 | return 'oauth_token=$token&oauth_token_secret=$tokenSecret'; 31 | } 32 | 33 | Map toJSON() { 34 | return { 35 | "oauth_token": token, 36 | "oauth_token_secret": tokenSecret 37 | }; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /lib/src/platform.dart: -------------------------------------------------------------------------------- 1 | library platform; 2 | 3 | import 'signature_method.dart'; 4 | 5 | /** 6 | * Configuration of OAuth1Authorization. 7 | * http://tools.ietf.org/html/rfc5849 8 | */ 9 | class Platform { 10 | final String _temporaryCredentialsRequestURI; 11 | final String _resourceOwnerAuthorizationURI; 12 | final String _tokenCredentialsRequestURI; 13 | final SignatureMethod _signatureMethod; 14 | 15 | Platform(this._temporaryCredentialsRequestURI, this._resourceOwnerAuthorizationURI, this._tokenCredentialsRequestURI, this._signatureMethod); 16 | 17 | /// Temporary Credentials Request URI 18 | /// http://tools.ietf.org/html/rfc5849#section-2.1 19 | String get temporaryCredentialsRequestURI => _temporaryCredentialsRequestURI; 20 | 21 | /// Resource Owner Authorization URI 22 | /// http://tools.ietf.org/html/rfc5849#section-2.2 23 | String get resourceOwnerAuthorizationURI => _resourceOwnerAuthorizationURI; 24 | 25 | /// Token Credentials Request URI 26 | /// http://tools.ietf.org/html/rfc5849#section-2.3 27 | String get tokenCredentialsRequestURI => _tokenCredentialsRequestURI; 28 | 29 | /// Signature Method 30 | /// http://tools.ietf.org/html/rfc5849#section-3.4 31 | SignatureMethod get signatureMethod => _signatureMethod; 32 | } 33 | -------------------------------------------------------------------------------- /lib/src/signature_method.dart: -------------------------------------------------------------------------------- 1 | library signature_method; 2 | 3 | import 'dart:convert'; 4 | import 'package:crypto/crypto.dart'; 5 | 6 | typedef String Sign(String key, String text); 7 | 8 | /** 9 | * A class abstracting Signature Method. 10 | * http://tools.ietf.org/html/rfc5849#section-3.4 11 | */ 12 | class SignatureMethod { 13 | final String _name; 14 | final Sign _sign; 15 | 16 | /// A constructor of SignatureMethod. 17 | SignatureMethod(this._name, this._sign); 18 | 19 | /// Signature Method Name 20 | String get name => _name; 21 | 22 | /// Sign data by key. 23 | String sign(String key, String text) => _sign(key, text); 24 | } 25 | 26 | /** 27 | * A abstract class contains Signature Methods. 28 | */ 29 | abstract class SignatureMethods { 30 | /// http://tools.ietf.org/html/rfc5849#section-3.4.2 31 | static final SignatureMethod HMAC_SHA1 = new SignatureMethod("HMAC-SHA1", (key, text) { 32 | Hmac hmac = new Hmac(sha1, key.codeUnits); 33 | List bytes = hmac.convert(text.codeUnits).bytes; 34 | 35 | // The output of the HMAC signing function is a binary 36 | // string. This needs to be base64 encoded to produce 37 | // the signature string. 38 | return BASE64.encode(bytes); 39 | }); 40 | 41 | /// http://tools.ietf.org/html/rfc5849#section-3.4.3 42 | /// TODO: Implement RSA-SHA1 43 | 44 | /// http://tools.ietf.org/html/rfc5849#section-3.4.4 45 | static final SignatureMethod PLAINTEXT = new SignatureMethod("PLAINTEXT", (key, text) { 46 | return key; 47 | }); 48 | } 49 | -------------------------------------------------------------------------------- /pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: oauth1 2 | version: 0.3.1 3 | description: A pub package of OAuth 1.0 (RFC 5849) library. 4 | dependencies: 5 | crypto: any 6 | formler: any 7 | http: any 8 | unittest: any 9 | uuid: any 10 | -------------------------------------------------------------------------------- /test/authorization_test.dart: -------------------------------------------------------------------------------- 1 | library authorization_test; 2 | 3 | import 'package:unittest/unittest.dart'; 4 | import 'package:http/http.dart' as http; 5 | import 'package:oauth1/oauth1.dart'; 6 | 7 | void main() { 8 | Platform twitter1_1 = new Platform( 9 | 'https://api.twitter.com/oauth/request_token', 10 | 'https://api.twitter.com/oauth/authorize', 11 | 'https://api.twitter.com/oauth/access_token', 12 | SignatureMethods.HMAC_SHA1); 13 | const String apiKey = 'LLDeVY0ySvjoOVmJ2XgBItvTV'; 14 | const String apiSecret = 'JmEpkWXXmY7BYoQor5AyR84BD2BiN47GIBUPXn3bopZqodJ0MV'; 15 | ClientCredentials clientCredentials = new ClientCredentials(apiKey, apiSecret); 16 | 17 | test('request temporary credentials', () { 18 | Authorization auth = new Authorization(clientCredentials, twitter1_1, new http.Client()); 19 | return auth.requestTemporaryCredentials(); 20 | }); 21 | } 22 | --------------------------------------------------------------------------------