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+ }
0 commit comments