Skip to content

Commit

Permalink
basic auth0 integration
Browse files Browse the repository at this point in the history
  • Loading branch information
YannMarti committed May 12, 2022
1 parent f010872 commit 9c5b5d1
Show file tree
Hide file tree
Showing 10 changed files with 274 additions and 26 deletions.
3 changes: 3 additions & 0 deletions vidaia/android/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,9 @@ android {
targetSdkVersion flutter.targetSdkVersion
versionCode flutterVersionCode.toInteger()
versionName flutterVersionName
manifestPlaceholders += [
'appAuthRedirectScheme': 'com.auth0.vidaia'
]
}

buildTypes {
Expand Down
13 changes: 8 additions & 5 deletions vidaia/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,8 @@ import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:get_it/get_it.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:vidaia/pages/home/home_page_loader.dart';
import 'package:vidaia/pages/auth0_testing_page.dart';
import 'package:vidaia/repositories/dataRepository.dart';
import 'package:vidaia/pages/login_page.dart';

GetIt getIt = GetIt.instance;

Expand Down Expand Up @@ -35,10 +34,14 @@ const primaryColorDark = Color(0xFF112823);
const backgroundColor = Color(0xFFf8faf7);
const backgroundColorDark = Color(0xFFebeeea);

class MyApp extends StatelessWidget {
class MyApp extends StatefulWidget {
MyApp({Key? key}) : super(key: key);

// This widget is the root of your application.
@override
State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
@override
Widget build(BuildContext context) {
return MaterialApp(
Expand Down Expand Up @@ -91,7 +94,7 @@ class MyApp extends StatelessWidget {
),
),
darkTheme: ThemeData.dark(),
home: HomePage2(),
home: Auth0TestPage(),
);
}
}
131 changes: 131 additions & 0 deletions vidaia/lib/pages/auth0_testing_page.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
import 'package:flutter/material.dart';
import 'package:flutter_appauth/flutter_appauth.dart';
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
import 'package:vidaia/pages/profile_testing.dart';
import 'package:vidaia/utils/auth0.dart';

import 'login_testing.dart';
final FlutterAppAuth appAuth = FlutterAppAuth();
final FlutterSecureStorage secureStorage = const FlutterSecureStorage();
const AUTH0_DOMAIN = 'saynode.eu.auth0.com';
const AUTH0_CLIENT_ID = 'NtesFp8kbFYekf05rleULMSdBS5hEWRN';

const AUTH0_REDIRECT_URI = 'com.auth0.vidaia://login-callback';
const AUTH0_ISSUER = 'https://$AUTH0_DOMAIN';

class Auth0TestPage extends StatefulWidget {

Auth0TestPage();

@override
State<Auth0TestPage> createState() => _Auth0TestPageState();
}

class _Auth0TestPageState extends State<Auth0TestPage> {
bool isBusy = false;
bool isLoggedIn = false;
String errorMessage = '';
String? name;
String? picture;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Auth0 Test'),
),
body: Center(
child: isBusy
? CircularProgressIndicator()
: isLoggedIn
? Profile(logoutAction, name!, picture!)
: Login(loginAction, errorMessage),
),
);
}
Future<void> loginAction() async {
setState(() {
isBusy = true;
errorMessage = '';
});

try {
final AuthorizationTokenResponse? result =
await appAuth.authorizeAndExchangeCode(
AuthorizationTokenRequest(
AUTH0_CLIENT_ID,
AUTH0_REDIRECT_URI,
issuer: 'https://$AUTH0_DOMAIN',
scopes: ['openid', 'profile', 'offline_access'],
// promptValues: ['login']
),
);

final idToken = parseIdToken(result!.idToken!);
final profile = await getUserDetails(result.accessToken!);

await secureStorage.write(
key: 'refresh_token', value: result.refreshToken);

setState(() {
isBusy = false;
isLoggedIn = true;
name = idToken['name'];
picture = profile['picture'];
});
} catch (e, s) {
print('login error: $e - stack: $s');

setState(() {
isBusy = false;
isLoggedIn = false;
errorMessage = e.toString();
});
}
}

void logoutAction() async {
await secureStorage.delete(key: 'refresh_token');
setState(() {
isLoggedIn = false;
isBusy = false;
});
}
@override
void initState() {
initAction();
super.initState();
}

void initAction() async {
final storedRefreshToken = await secureStorage.read(key: 'refresh_token');
if (storedRefreshToken == null) return;

setState(() {
isBusy = true;
});

try {
final response = await appAuth.token(TokenRequest(
AUTH0_CLIENT_ID,
AUTH0_REDIRECT_URI,
issuer: AUTH0_ISSUER,
refreshToken: storedRefreshToken,
));

final idToken = parseIdToken(response!.idToken!);
final profile = await getUserDetails(response.accessToken!);

secureStorage.write(key: 'refresh_token', value: response.refreshToken);

setState(() {
isBusy = false;
isLoggedIn = true;
name = idToken['name'];
picture = profile['picture'];
});
} catch (e, s) {
print('error on refresh token: $e - stack: $s');
logoutAction();
}
}
}
44 changes: 24 additions & 20 deletions vidaia/lib/pages/login_page.dart
Original file line number Diff line number Diff line change
Expand Up @@ -52,26 +52,30 @@ class LoginPage extends StatelessWidget {

@override
Widget build(BuildContext context) {
return Container(
color: primaryColor,
child: FlutterLogin(
userType: LoginUserType.name,
logo: const AssetImage('assets/images/vidaia-live-sustainably.png'),
messages:
LoginMessages(userHint: 'Email', passwordHint: 'password'.tr()),
onLogin: _authUser,
onSignup: _signupUser,
onSubmitAnimationCompleted: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => HomePage2()),
);
if (!mnemonicNoted) {
showMnemonicAlert(context);
}
},
onRecoverPassword: _recoverPassword,
),
return Column(
children: [
Container(
color: primaryColor,
child: FlutterLogin(
userType: LoginUserType.name,
logo: const AssetImage('assets/images/vidaia-live-sustainably.png'),
messages:
LoginMessages(userHint: 'Email', passwordHint: 'password'.tr()),
onLogin: _authUser,
onSignup: _signupUser,
onSubmitAnimationCompleted: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => HomePage2()),
);
if (!mnemonicNoted) {
showMnemonicAlert(context);
}
},
onRecoverPassword: _recoverPassword,
),
),
],
);
}
}
26 changes: 26 additions & 0 deletions vidaia/lib/pages/login_testing.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import 'package:flutter/material.dart';

class Login extends StatelessWidget {
final loginAction;
final String loginError;

const Login(this.loginAction, this.loginError);

@override
Widget build(BuildContext context) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
ElevatedButton(
onPressed: () {
loginAction();
},
child: Text('Login'),
),
Text(loginError),


],
);
}
}
39 changes: 39 additions & 0 deletions vidaia/lib/pages/profile_testing.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import 'package:flutter/material.dart';

class Profile extends StatelessWidget {
final logoutAction;
final String name;
final String picture;

Profile(this.logoutAction, this.name, this.picture);

@override
Widget build(BuildContext context) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Container(
width: 150,
height: 150,
decoration: BoxDecoration(
border: Border.all(color: Colors.blue, width: 4.0),
shape: BoxShape.circle,
image: DecorationImage(
fit: BoxFit.fill,
image: NetworkImage(picture),
),
),
),
SizedBox(height: 24.0),
Text('Name: $name'),
SizedBox(height: 48.0),
ElevatedButton(
onPressed: () {
logoutAction();
},
child: Text('Logout'),
),
],
);
}
}
25 changes: 25 additions & 0 deletions vidaia/lib/utils/auth0.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import 'dart:convert';
import 'package:http/http.dart' as http;
import 'package:vidaia/pages/auth0_testing_page.dart';

Map<String, dynamic> parseIdToken(String idToken) {
final parts = idToken.split(r'.');
assert(parts.length == 3);

return jsonDecode(
utf8.decode(base64Url.decode(base64Url.normalize(parts[1]))));
}

Future<Map<String, dynamic>> getUserDetails(String accessToken) async {
final url = Uri.parse('https://$AUTH0_DOMAIN/userinfo');
final response = await http.get(
url,
headers: {'Authorization': 'Bearer $accessToken'},
);

if (response.statusCode == 200) {
return jsonDecode(response.body);
} else {
throw Exception('Failed to get user details');
}
}
1 change: 1 addition & 0 deletions vidaia/lib/utils/globals.dart
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ Wallet? wallet;
String? qrCode;

bool mnemonicNoted = false;
String token = '';


//priv c337cf0b3c7c3e4b7f5480b985724e0f221120554459b5c247870d2789726089
Expand Down
16 changes: 15 additions & 1 deletion vidaia/pubspec.lock
Original file line number Diff line number Diff line change
Expand Up @@ -300,6 +300,20 @@ packages:
description: flutter
source: sdk
version: "0.0.0"
flutter_appauth:
dependency: "direct main"
description:
name: flutter_appauth
url: "https://pub.dartlang.org"
source: hosted
version: "2.4.2"
flutter_appauth_platform_interface:
dependency: transitive
description:
name: flutter_appauth_platform_interface
url: "https://pub.dartlang.org"
source: hosted
version: "4.1.0"
flutter_lints:
dependency: "direct dev"
description:
Expand Down Expand Up @@ -435,7 +449,7 @@ packages:
source: hosted
version: "0.15.0"
http:
dependency: transitive
dependency: "direct main"
description:
name: http
url: "https://pub.dartlang.org"
Expand Down
2 changes: 2 additions & 0 deletions vidaia/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ dependencies:
easy_localization: ^3.0.0
carousel_slider: ^4.0.0
flutter_secure_storage: ^5.0.2
http: ^0.13.4


# The following adds the Cupertino Icons font to your application.
Expand All @@ -55,6 +56,7 @@ dependencies:
url_launcher: ^6.1.0
contained_tab_bar_view: ^0.8.0
mobile_scanner: ^1.0.0
flutter_appauth: ^2.4.2

dev_dependencies:
flutter_test:
Expand Down

0 comments on commit 9c5b5d1

Please sign in to comment.