Skip to content

Commit da1e9d6

Browse files
author
Patrick FINKELSTEIN
committed
split API in multiple files
1 parent 8f5020b commit da1e9d6

6 files changed

Lines changed: 260 additions & 216 deletions

File tree

example/lib/main.dart

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,12 +42,17 @@ class StravaFlutterPage extends StatefulWidget {
4242
}
4343

4444
class _StravaFlutterPageState extends State<StravaFlutterPage> {
45+
46+
String clientID = "32212";
47+
final String redirectUrl = "http://localhost:8080";
48+
final String scope = 'profile:write';
49+
4550
final strava = Strava(
4651
"32212", // Put your Strava id app
4752
secret, // Put your secret key in secret.dart file
4853
"http://localhost:8080",
4954
'auto',
50-
'profile:read_all, profile:write', // The scope you need
55+
'profile:write', // The scope you need
5156
// Check https://developers.strava.com/docs/oauth-updates/ scope update
5257
);
5358

@@ -58,7 +63,7 @@ class _StravaFlutterPageState extends State<StravaFlutterPage> {
5863
}
5964

6065
void example() async {
61-
var resAuth = await strava.Auth();
66+
var resAuth = await strava.OAuth(clientID, redirectUrl, scope, secret);
6267

6368
if (resAuth) {
6469
DetailedAthlete athlete = await strava.getLoggedInAthlete();

lib/API/Oauth.dart

Lines changed: 232 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,232 @@
1+
// Oauth.dart
2+
3+
import 'package:http/http.dart' as http;
4+
import 'dart:async';
5+
import 'dart:io';
6+
import 'dart:convert';
7+
8+
import 'constants.dart';
9+
import 'token.dart';
10+
11+
12+
import 'package:url_launcher/url_launcher.dart';
13+
import 'package:shared_preferences/shared_preferences.dart';
14+
15+
16+
17+
//===========================================
18+
// Code related to Authorization processs
19+
//===========================================
20+
21+
abstract class Auth {
22+
23+
24+
StreamController<String> onCodeReceived = StreamController();
25+
26+
// Save the token and the expiry date
27+
void _saveToken(String token, int expire, String scope) async {
28+
final prefs = await SharedPreferences.getInstance();
29+
prefs.setString('token', token);
30+
prefs.setInt('expire', expire); // Stored in seconds
31+
prefs.setString('scope', scope);
32+
33+
print('token saved!!!');
34+
}
35+
36+
// get the stored token and expiry date
37+
Future<Token> getStoredToken() async {
38+
final prefs = await SharedPreferences.getInstance();
39+
var localToken = Token();
40+
try {
41+
localToken.accessToken = prefs.getString('token').toString();
42+
localToken.expiresAt = prefs.getInt('expire');
43+
localToken.scope = prefs.getString('scope');
44+
45+
} catch (error) {
46+
print('Error getting the key');
47+
localToken.accessToken = null;
48+
localToken.expiresAt = null;
49+
localToken.scope = null;
50+
}
51+
52+
if (localToken.expiresAt != null) {
53+
var dateExpired =
54+
DateTime.fromMillisecondsSinceEpoch(localToken.expiresAt);
55+
var disp = dateExpired.day.toString() +
56+
dateExpired.month.toString() +
57+
dateExpired.hour.toString();
58+
print('stored token ${localToken.accessToken} expires: $disp ');
59+
}
60+
61+
return (localToken);
62+
}
63+
64+
65+
66+
Map<String, String> createHeader(String token) {
67+
return {'Authorization': 'Bearer $token'};
68+
69+
}
70+
71+
// Get the code from Strava server
72+
Future<void> _getStravaCode(
73+
String clientID, String redirectUrl, String scope) async {
74+
print('Welcome to getStravaCode');
75+
var code = "";
76+
var params = '?' +
77+
'client_id=' +
78+
clientID +
79+
'&redirect_uri=' +
80+
redirectUrl +
81+
'&response_type=' +
82+
'code' +
83+
'&approval_prompt=' +
84+
'auto' +
85+
// '&scope=' + 'read,read_all,profile:read_all';
86+
'&scope=' +
87+
scope;
88+
89+
var reqAuth = authorizationEndpoint + params;
90+
print('---> $reqAuth');
91+
92+
closeWebView();
93+
launch(reqAuth,
94+
forceWebView: true, forceSafariVC: true, enableJavaScript: true);
95+
96+
// Launch small http server to collect the answer from Strava
97+
//------------------------------------------------------------
98+
final server =
99+
await HttpServer.bind(InternetAddress.loopbackIPv4, 8080, shared: true);
100+
server.listen((HttpRequest request) async {
101+
// Get the answer from Strava
102+
final uri = request.uri;
103+
104+
code = uri.queryParameters["code"];
105+
final error = uri.queryParameters["error"];
106+
print('---> code $code, error $error');
107+
108+
closeWebView();
109+
server.close(force: true);
110+
111+
onCodeReceived.add(code);
112+
});
113+
114+
print('End of getStravaCode');
115+
}
116+
117+
Future<Token> _getStravaToken(String clientID, String secret, String code) async {
118+
Token _answer = Token();
119+
120+
print('---> Entering getStravaToken!!');
121+
var urlToken = tokenEndpoint +
122+
'?client_id=' +
123+
clientID +
124+
'&client_secret=' +
125+
secret + // Put your own secret in secret.dart
126+
'&code=' +
127+
code +
128+
'&grant_type=' +
129+
'authorization_code';
130+
131+
print('----> urlToken $urlToken');
132+
133+
var value = await http.post(urlToken);
134+
135+
// responseToken.then((value) {
136+
print('----> body ${value.body}');
137+
138+
if (value.body.contains('message')) {
139+
// This is not the normal message
140+
print('---> Error in getStravaToken');
141+
// will return _answer null
142+
} else {
143+
var tokenBody = json.decode(value.body);
144+
// Todo: handle error with message "Authorization Error" and errors != null
145+
var _body = Token.fromJson(tokenBody);
146+
var accessToken = _body.accessToken;
147+
var refreshToken = _body.refreshToken;
148+
var expiresAt = _body.expiresAt * 1000;
149+
150+
_answer.accessToken = accessToken;
151+
_answer.refreshToken = refreshToken;
152+
_answer.expiresAt = expiresAt;
153+
}
154+
155+
return (_answer);
156+
// });
157+
}
158+
159+
bool _isTokenExpired(Token token) {
160+
final DateTime _expiryDate =
161+
DateTime.fromMillisecondsSinceEpoch(token.expiresAt);
162+
return (_expiryDate.isBefore(DateTime.now()));
163+
}
164+
165+
Future<bool> OAuth(String clientID, String redirectUrl, String scope, String secret) async {
166+
bool isExpired = true;
167+
bool returnValue = false;
168+
169+
final Token tokenStored = await getStoredToken();
170+
final String _token = tokenStored.accessToken;
171+
172+
// Check if the token is not expired
173+
if (_token != "null") {
174+
print('----> token has been stored before! ${tokenStored.accessToken}');
175+
176+
isExpired = _isTokenExpired(tokenStored);
177+
}
178+
179+
// Check if access token has been stored previously or expired
180+
if ((_token == "null") || (isExpired)) {
181+
182+
// todo: if accessToken is expired use the refresh token
183+
// to get a new access code
184+
await _getStravaCode(clientID, redirectUrl, scope);
185+
186+
onCodeReceived.stream.listen((stravaCode) async {
187+
if (stravaCode != null) {
188+
var answer = await _getStravaToken(clientID, secret, stravaCode);
189+
190+
print('---> answer ${answer.expiresAt} , ${answer.accessToken}');
191+
192+
// Save the token information
193+
if (answer.accessToken != null && answer.expiresAt != null) {
194+
_saveToken(answer.accessToken, answer.expiresAt, scope);
195+
}
196+
197+
returnValue = true;
198+
} else {
199+
print('----> code is still null');
200+
returnValue = false;
201+
}
202+
});
203+
} else {
204+
205+
returnValue = true;
206+
}
207+
208+
return (returnValue);
209+
}
210+
211+
Future<void> deAuthorize() async {
212+
String returnValue;
213+
214+
var _token = await getStoredToken();
215+
216+
var header = createHeader(_token.accessToken)
217+
if (header != null) {
218+
final reqDeAuthorize = "https://www.strava.com/oauth/deauthorize";
219+
var rep = await http.post(reqDeAuthorize, headers: header);
220+
if (rep.statusCode == 200) {
221+
print('DeAuthorize done');
222+
_saveToken(null, null);
223+
} else {
224+
print('problem in deAuthorize request');
225+
// Todo add an error code
226+
}
227+
}
228+
}
229+
230+
231+
232+
}

lib/API/constants.dart

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,9 @@ enum ErrorCode {
55
headerIsEmpty,
66
tokenIsInvalid,
77
unknownError,
8-
}
8+
}
9+
10+
11+
12+
final tokenEndpoint = "https://www.strava.com/oauth/token";
13+
final authorizationEndpoint = "https://www.strava.com/oauth/authorize";

0 commit comments

Comments
 (0)