Added Twitter OAuth1
This commit is contained in:
parent
a226d29514
commit
c96980a887
9 changed files with 90 additions and 49 deletions
|
@ -1,19 +0,0 @@
|
||||||
name: "angel3_auth_twitter"
|
|
||||||
version: 3.0.0
|
|
||||||
description: "package:angel3_auth strategy for Twitter login. Auto-signs requests."
|
|
||||||
homepage: "https://github.com/angel-dart/auth_twitter.git"
|
|
||||||
publish_to: none
|
|
||||||
environment:
|
|
||||||
sdk: ">=2.10.0 <3.0.0"
|
|
||||||
dependencies:
|
|
||||||
angel_auth: ^2.0.0
|
|
||||||
angel_framework: ^2.0.0
|
|
||||||
http: ^0.13.0
|
|
||||||
path: ^1.0.0
|
|
||||||
twitter:
|
|
||||||
git:
|
|
||||||
url: https://github.com/dukefirehawk/twitter.dart.git
|
|
||||||
ref: sdk-2.12.x
|
|
||||||
dev_dependencies:
|
|
||||||
logging: ^1.0.0
|
|
||||||
lints: ^1.0.0
|
|
|
@ -1,5 +1,13 @@
|
||||||
# Change Log
|
# Change Log
|
||||||
|
|
||||||
|
## 6.0.0-beta.1
|
||||||
|
|
||||||
|
* Updated to SDK 2.16.x
|
||||||
|
|
||||||
|
## 5.0.0
|
||||||
|
|
||||||
|
* Skipped release
|
||||||
|
|
||||||
## 4.0.0
|
## 4.0.0
|
||||||
|
|
||||||
* Migrated to support Dart SDK 2.12.x NNBD
|
* Migrated to support Dart SDK 2.12.x NNBD
|
|
@ -1,10 +1,10 @@
|
||||||
# Angel3 Auth Twitter
|
# Angel3 Twitter OAuth1
|
||||||
|
|
||||||
![Pub Version (including pre-releases)](https://img.shields.io/pub/v/angel3_auth_twitter?include_prereleases)
|
![Pub Version (including pre-releases)](https://img.shields.io/pub/v/angel3_auth_twitter?include_prereleases)
|
||||||
![Null Safety](https://img.shields.io/badge/null-safety-brightgreen)](<https://dart.dev/null-safety>)
|
![Null Safety](https://img.shields.io/badge/null-safety-brightgreen)](<https://dart.dev/null-safety>)
|
||||||
[![Gitter](https://img.shields.io/gitter/room/angel_dart/discussion)](https://gitter.im/angel_dart/discussion)
|
[![Gitter](https://img.shields.io/gitter/room/angel_dart/discussion)](https://gitter.im/angel_dart/discussion)
|
||||||
[![License](https://img.shields.io/github/license/dukefirehawk/angel)](https://github.com/dukefirehawk/angel/tree/master/packages/auth_twitter/LICENSE)
|
[![License](https://img.shields.io/github/license/dukefirehawk/angel)](https://github.com/dukefirehawk/angel/tree/master/packages/auth_twitter/LICENSE)
|
||||||
|
|
||||||
Angel3 authentication strategy for Twitter login.
|
Angel3 authentication strategy using Twitter OAuth 1.0a.
|
||||||
|
|
||||||
See the [example](example/server.dart);
|
See the [example](example/example.dart);
|
|
@ -1,9 +1,9 @@
|
||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
import 'package:angel_auth/angel_auth.dart';
|
import 'package:angel3_auth/angel3_auth.dart';
|
||||||
import 'package:angel_auth_twitter/angel_auth_twitter.dart';
|
import 'package:angel3_auth_twitter/angel3_auth_twitter.dart';
|
||||||
import 'package:angel_framework/angel_framework.dart';
|
import 'package:angel3_framework/angel3_framework.dart';
|
||||||
import 'package:angel_framework/http.dart';
|
import 'package:angel3_framework/http.dart';
|
||||||
import 'package:logging/logging.dart';
|
import 'package:logging/logging.dart';
|
||||||
|
|
||||||
class _User {
|
class _User {
|
||||||
|
@ -38,7 +38,7 @@ void main() async {
|
||||||
'http://localhost:3000/auth/twitter/callback',
|
'http://localhost:3000/auth/twitter/callback',
|
||||||
),
|
),
|
||||||
(twit, req, res) async {
|
(twit, req, res) async {
|
||||||
var response = await twit.twitterClient.get(Uri.parse(
|
var response = await twit.client.get(Uri.parse(
|
||||||
'https://api.twitter.com/1.1/account/verify_credentials.json'));
|
'https://api.twitter.com/1.1/account/verify_credentials.json'));
|
||||||
var userData = json.decode(response.body) as Map;
|
var userData = json.decode(response.body) as Map;
|
||||||
return _User(userData['screen_name'] as String);
|
return _User(userData['screen_name'] as String);
|
||||||
|
@ -53,9 +53,7 @@ void main() async {
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
app
|
app.get('/', auth.authenticate('twitter'));
|
||||||
..fallback(auth.decodeJwt)
|
|
||||||
..get('/', auth.authenticate('twitter'));
|
|
||||||
|
|
||||||
app.get(
|
app.get(
|
||||||
'/auth/twitter/callback',
|
'/auth/twitter/callback',
|
||||||
|
@ -74,7 +72,7 @@ void main() async {
|
||||||
chain([
|
chain([
|
||||||
requireAuthentication<_User>(),
|
requireAuthentication<_User>(),
|
||||||
(req, res) {
|
(req, res) {
|
||||||
var user = req.container.make<_User>();
|
var user = req.container!.make<_User>();
|
||||||
res.write('Your Twitter handle is ${user.handle}');
|
res.write('Your Twitter handle is ${user.handle}');
|
||||||
return false;
|
return false;
|
||||||
},
|
},
|
|
@ -1,11 +1,12 @@
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
import 'package:angel_auth/angel_auth.dart';
|
import 'dart:io';
|
||||||
import 'package:angel_framework/angel_framework.dart';
|
import 'package:angel3_auth/angel3_auth.dart';
|
||||||
|
import 'package:angel3_framework/angel3_framework.dart';
|
||||||
import 'package:http/http.dart' as http;
|
import 'package:http/http.dart' as http;
|
||||||
import 'package:oauth/oauth.dart' as oauth;
|
|
||||||
import 'package:path/path.dart' as p;
|
import 'package:path/path.dart' as p;
|
||||||
import 'package:twitter/twitter.dart';
|
import 'package:oauth1/oauth1.dart' as oauth;
|
||||||
|
import 'package:dart_twitter_api/twitter_api.dart';
|
||||||
|
|
||||||
/// Authenticates users by connecting to Twitter's API.
|
/// Authenticates users by connecting to Twitter's API.
|
||||||
class TwitterStrategy<User> extends AuthStrategy<User> {
|
class TwitterStrategy<User> extends AuthStrategy<User> {
|
||||||
|
@ -15,7 +16,7 @@ class TwitterStrategy<User> extends AuthStrategy<User> {
|
||||||
/// A callback that uses Twitter to authenticate a [User].
|
/// A callback that uses Twitter to authenticate a [User].
|
||||||
///
|
///
|
||||||
/// As always, return `null` if authentication fails.
|
/// As always, return `null` if authentication fails.
|
||||||
final FutureOr<User> Function(Twitter, RequestContext, ResponseContext)
|
final FutureOr<User> Function(TwitterApi, RequestContext, ResponseContext)
|
||||||
verifier;
|
verifier;
|
||||||
|
|
||||||
/// A callback that is triggered when an OAuth2 error occurs (i.e. the user declines to login);
|
/// A callback that is triggered when an OAuth2 error occurs (i.e. the user declines to login);
|
||||||
|
@ -25,17 +26,47 @@ class TwitterStrategy<User> extends AuthStrategy<User> {
|
||||||
/// The root of Twitter's API. Defaults to `'https://api.twitter.com'`.
|
/// The root of Twitter's API. Defaults to `'https://api.twitter.com'`.
|
||||||
final Uri baseUrl;
|
final Uri baseUrl;
|
||||||
|
|
||||||
oauth.Client _client;
|
oauth.Client? _client;
|
||||||
|
|
||||||
/// The underlying [oauth.Client] used to query Twitter.
|
/// The underlying [oauth.Client] used to query Twitter.
|
||||||
oauth.Client get client => _client;
|
oauth.Client get client => _client!;
|
||||||
|
|
||||||
TwitterStrategy(this.options, this.verifier, this.onError,
|
TwitterStrategy(this.options, this.verifier, this.onError,
|
||||||
{http.BaseClient client, Uri baseUrl})
|
{http.BaseClient? client, Uri? baseUrl})
|
||||||
: baseUrl = baseUrl ?? Uri.parse('https://api.twitter.com') {
|
: baseUrl = baseUrl ?? Uri.parse('https://api.twitter.com') {
|
||||||
var tokens = oauth.Tokens(
|
// define platform (server)
|
||||||
consumerId: options.clientId, consumerKey: options.clientSecret);
|
final oauth.Platform platform = oauth.Platform(
|
||||||
_client = oauth.Client(tokens, client: client);
|
'$baseUrl/oauth/request_token', // temporary credentials request
|
||||||
|
'$baseUrl/oauth/authorize', // resource owner authorization
|
||||||
|
'$baseUrl/oauth/access_token', // token credentials request
|
||||||
|
oauth.SignatureMethods.hmacSha1 // signature method
|
||||||
|
);
|
||||||
|
|
||||||
|
// define client credentials (consumer keys)
|
||||||
|
final oauth.ClientCredentials clientCredentials =
|
||||||
|
oauth.ClientCredentials(options.clientId, options.clientSecret);
|
||||||
|
|
||||||
|
// create Authorization object with client credentials and platform definition
|
||||||
|
final oauth.Authorization auth =
|
||||||
|
oauth.Authorization(clientCredentials, platform);
|
||||||
|
|
||||||
|
// request temporary credentials (request tokens)
|
||||||
|
auth.requestTemporaryCredentials('oob').then((res) {
|
||||||
|
// redirect to authorization page
|
||||||
|
print(
|
||||||
|
"Open with your browser: ${auth.getResourceOwnerAuthorizationURI(res.credentials.token)}");
|
||||||
|
|
||||||
|
// get verifier (PIN)
|
||||||
|
stdout.write("PIN: ");
|
||||||
|
String verifier = stdin.readLineSync() ?? '';
|
||||||
|
|
||||||
|
// request token credentials (access tokens)
|
||||||
|
return auth.requestTokenCredentials(res.credentials, verifier);
|
||||||
|
}).then((res) {
|
||||||
|
// create Client object
|
||||||
|
_client = oauth.Client(
|
||||||
|
platform.signatureMethod, clientCredentials, res.credentials);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Handle a response from Twitter.
|
/// Handle a response from Twitter.
|
||||||
|
@ -60,7 +91,7 @@ class TwitterStrategy<User> extends AuthStrategy<User> {
|
||||||
|
|
||||||
/// Get an access token.
|
/// Get an access token.
|
||||||
Future<Map<String, String>> getAccessToken(String token, String verifier) {
|
Future<Map<String, String>> getAccessToken(String token, String verifier) {
|
||||||
return _client.post(
|
return client.post(
|
||||||
baseUrl.replace(path: p.join(baseUrl.path, 'oauth/access_token')),
|
baseUrl.replace(path: p.join(baseUrl.path, 'oauth/access_token')),
|
||||||
headers: {
|
headers: {
|
||||||
'accept': 'application/json'
|
'accept': 'application/json'
|
||||||
|
@ -75,7 +106,7 @@ class TwitterStrategy<User> extends AuthStrategy<User> {
|
||||||
|
|
||||||
/// Get a request token.
|
/// Get a request token.
|
||||||
Future<Map<String, String>> getRequestToken() {
|
Future<Map<String, String>> getRequestToken() {
|
||||||
return _client.post(
|
return client.post(
|
||||||
baseUrl.replace(path: p.join(baseUrl.path, 'oauth/request_token')),
|
baseUrl.replace(path: p.join(baseUrl.path, 'oauth/request_token')),
|
||||||
headers: {
|
headers: {
|
||||||
'accept': 'application/json'
|
'accept': 'application/json'
|
||||||
|
@ -86,8 +117,8 @@ class TwitterStrategy<User> extends AuthStrategy<User> {
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<User> authenticate(RequestContext req, ResponseContext res,
|
Future<User?> authenticate(RequestContext req, ResponseContext res,
|
||||||
[AngelAuthOptions options]) async {
|
[AngelAuthOptions? options]) async {
|
||||||
try {
|
try {
|
||||||
if (options != null) {
|
if (options != null) {
|
||||||
var result = await authenticateCallback(req, res, options);
|
var result = await authenticateCallback(req, res, options);
|
||||||
|
@ -107,7 +138,7 @@ class TwitterStrategy<User> extends AuthStrategy<User> {
|
||||||
}
|
}
|
||||||
} on TwitterAuthorizationException catch (e) {
|
} on TwitterAuthorizationException catch (e) {
|
||||||
var result = await onError(e, req, res);
|
var result = await onError(e, req, res);
|
||||||
await req.app.executeHandler(result, req, res);
|
await req.app?.executeHandler(result, req, res);
|
||||||
await res.close();
|
await res.close();
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -124,8 +155,13 @@ class TwitterStrategy<User> extends AuthStrategy<User> {
|
||||||
var token = req.queryParameters['oauth_token'] as String;
|
var token = req.queryParameters['oauth_token'] as String;
|
||||||
var verifier = req.queryParameters['oauth_verifier'] as String;
|
var verifier = req.queryParameters['oauth_verifier'] as String;
|
||||||
var loginData = await getAccessToken(token, verifier);
|
var loginData = await getAccessToken(token, verifier);
|
||||||
var twitter = Twitter(this.options.clientId, this.options.clientSecret,
|
var twitter = TwitterApi(
|
||||||
loginData['oauth_token'], loginData['oauth_token_secret']);
|
client: TwitterClient(
|
||||||
|
consumerKey: this.options.clientId,
|
||||||
|
consumerSecret: this.options.clientSecret,
|
||||||
|
token: loginData['oauth_token'] ?? '',
|
||||||
|
secret: loginData['oauth_token_secret'] ?? ''));
|
||||||
|
|
||||||
return await this.verifier(twitter, req, res);
|
return await this.verifier(twitter, req, res);
|
||||||
} on TwitterAuthorizationException catch (e) {
|
} on TwitterAuthorizationException catch (e) {
|
||||||
return await onError(e, req, res);
|
return await onError(e, req, res);
|
18
packages/auth_twitter/pubspec.yaml
Normal file
18
packages/auth_twitter/pubspec.yaml
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
name: "angel3_auth_twitter"
|
||||||
|
description: Angel3 authentication strategy for Twitter login. Auto-signs requests.
|
||||||
|
version: 3.0.0
|
||||||
|
homepage: https://angel3-framework.web.app/
|
||||||
|
repository: https://github.com/dukefirehawk/angel/tree/master/packages/auth_twitter
|
||||||
|
publish_to: none
|
||||||
|
environment:
|
||||||
|
sdk: ">=2.16.0 <3.0.0"
|
||||||
|
dependencies:
|
||||||
|
angel3_auth: ^6.0.0
|
||||||
|
angel3_framework: ^6.0.0
|
||||||
|
http: ^0.13.0
|
||||||
|
path: ^1.0.0
|
||||||
|
oauth1: ^2.0.0
|
||||||
|
dart_twitter_api: ^0.5.6+1
|
||||||
|
dev_dependencies:
|
||||||
|
logging: ^1.0.0
|
||||||
|
lints: ^2.0.0
|
Loading…
Reference in a new issue