Prerequisites
Tools required to follow the article.
- Flutter SDK.
- Android Studio or VS Code.
- Emulator or an Android device
- Background knowledge of Flutter and Dart
If you have checked out the official documentation of Auth0 you will find out that there is no SDK for flutter yet, I have a positive feeling it might come in later. But nothing to worry Flutter developers are not left out from using their services, hence Auth0 has an official package that gives you access to their product service.
Setup
Building UI is not our main focus, So please clone the started code here So let’s get into the real business
Auth0
Auth0 is a flexible, drop-in solution to add authentication and authorization services to your applications. Your team and organization can avoid the cost, time, and risk that comes with building your own solution to authenticate and authorize users.
Lets get started by installing the Auth0 package form the package manager, Open the clone code in our favourite text editor, go to our
pubspec.yaml` and add the following code to our dependency
flutter_auth0: ^0.5.0
Time to write some code One more thing before we write code.
Auth0 Account Setup
In other to use the Auth0 service we will have to create an account if we already have an account, Login head over to our dashboard.
Click on the Create Application and give our app a name and select Native as the app type. Head over to the setting and copy the Domain
and ClientId
and fill them in the constant.dart
respectively. Lastly, Scroll down and click on the Show Advance Settings, on the Grant Types ensure to check the Password checkbox.
Signup
Alright at this point I believe we have an account and created our application with Auth0
, with let’s head on to implementing signup.
Open the signup.dart on your editor import constant.dart
and the Auth0
package we installed earlier by adding the following code at the top of our signup.dart
import 'package:flutter_auth0/flutter_auth0.dart';
import 'constant.dart';
Let’s declare a variable with an instance of Auth0
which is from the package and also declare it inside an initState
method. After the password variable, let’s add the code below.
Auth0 auth;
@override
void initState() {
// TODO: implement initState
super.initState();
Auth0 auth = Auth0(baseUrl: 'https://$domain/', clientId: clientId);
}
Let’s create a method to handle the signup process by adding the code above our build method:
signup({String email, String password}) async {
try {
await auth.auth.createUser({
'email': email,
'password': password,
'connection': 'Username-Password-Authentication'
});
} catch (e) {
print(e);
}
}
Before calling the signup function let us handle errors and events. First, let’s create a boolean variable and set it false. Just after the declaration of the auth variable let’s add the following code:
- bool busy = false;
Also, let’s update the Sign button with the following code:
InkWell(
onTap: null,
child: Container(
height: 40,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(5),
color: Colors.blue,
),
child: Center(
child: !busy
? Text(
"Signup",
style: TextStyle(
color: Colors.white,
fontSize: 20,
fontWeight: FontWeight.bold,
),
)
: CircularProgressIndicator(
strokeWidth: 2,
valueColor:
AlwaysStoppedAnimation<Color>(Colors.white),
),
),
),
),
Also, let’s update our signup method with the following code
signup({String email, String password}) async {
try {
setState(() {
busy = true;
});
await auth.auth.createUser({
'email': email,
'password': password,
'connection': 'Username-Password-Authentication'
});
setState(() {
busy = false;
});
_scaffoldKey.currentState.showSnackBar(
SnackBar(
backgroundColor: Colors.green,
content: new Text("$email has successfully logged in"),
),
);
} catch (e) {
setState(() {
busy = false;
});
_scaffoldKey.currentState.showSnackBar(
SnackBar(
backgroundColor: Colors.red,
content: new Text(e),
),
);
print(e);
}
}
Now we have to call our signup method immediately the signup button is clicked, we can achieve by updating the onTap
parameter with the code below:
onTap: () async {
await signup(
email: emailController.text,
password: passwordController.text,
);
},
our signup.dart
should look similar to the code below
import 'package:auth0/login.dart';
import 'package:flutter/material.dart';
import 'package:flutter_auth0/flutter_auth0.dart';
import 'constant.dart';
class Signup extends StatefulWidget {
@override
_SignupState createState() => _SignupState();
}
class _SignupState extends State<Signup> {
final GlobalKey<ScaffoldState> _scaffoldKey = new GlobalKey<ScaffoldState>();
final emailController = TextEditingController();
final passwordController = TextEditingController();
Auth0 auth;
bool busy = false;
@override
void initState() {
// TODO: implement initState
super.initState();
Auth0 auth = Auth0(baseUrl: 'https://$domain/', clientId: clientId);
}
signup({String email, String password}) async {
try {
setState(() {
busy = true;
});
await auth.auth.createUser({
'email': email,
'password': password,
'connection': 'Username-Password-Authentication'
});
setState(() {
busy = false;
});
_scaffoldKey.currentState.showSnackBar(
SnackBar(
backgroundColor: Colors.green,
content: new Text("$email has successfully logged in"),
),
);
} catch (e) {
setState(() {
busy = false;
});
_scaffoldKey.currentState.showSnackBar(
SnackBar(
backgroundColor: Colors.red,
content: new Text(e),
),
);
print(e);
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
key: _scaffoldKey,
appBar: AppBar(
title: Text("Signup"),
),
body: SafeArea(
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 20.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"Signup",
style: TextStyle(
fontSize: 36,
fontWeight: FontWeight.bold,
color: Colors.black,
),
),
SizedBox(height: 20),
TextField(
controller: emailController,
decoration: InputDecoration(
labelText: "Email",
border: OutlineInputBorder(
borderSide: BorderSide(color: Colors.black, width: 1.0),
),
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.black, width: 2.0),
),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.black, width: 2.0),
),
),
),
SizedBox(height: 20),
TextField(
controller: passwordController,
decoration: InputDecoration(
labelText: "Password",
border: OutlineInputBorder(
borderSide: BorderSide(color: Colors.black, width: 1.0),
),
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.black, width: 2.0),
),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.black, width: 2.0),
),
),
),
SizedBox(height: 20),
InkWell(
onTap: () async {
await signup(
email: emailController.text,
password: passwordController.text,
);
},
child: Container(
height: 40,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(5),
color: Colors.blue,
),
child: Center(
child: !busy
? Text(
"Signup",
style: TextStyle(
color: Colors.white,
fontSize: 20,
fontWeight: FontWeight.bold,
),
)
: CircularProgressIndicator(
strokeWidth: 2,
valueColor:
AlwaysStoppedAnimation<Color>(Colors.white),
),
),
),
),
SizedBox(height: 30),
InkWell(
onTap: () => Navigator.push(
context,
MaterialPageRoute(
builder: (context) => Login(),
),
),
child: Row(
children: [
Text(
"Already have Account? ",
style: TextStyle(
fontSize: 13,
color: Colors.black,
),
),
Text(
"Login",
style: TextStyle(
fontSize: 13,
color: Colors.blue,
),
)
],
),
)
],
),
),
),
);
}
}
Login
The login will be a replica of what we just did for signup on that it will have It’s on method instead of the signup method. So let’s go ahead and replicate what we did for signup in the login.dart and replace the signup method with the code below:
login({String email, String password}) async {
try {
setState(() {
busy = true;
});
await auth.auth.passwordRealm({
'username': email,
'password': password,
'realm': 'Username-Password-Authentication'
});
setState(() {
busy = false;
});
_scaffoldKey.currentState.showSnackBar(
SnackBar(
backgroundColor: Colors.green,
content: new Text("$email has successfully logged in"),
),
);
} catch (e) {
setState(() {
busy = false;
});
_scaffoldKey.currentState.showSnackBar(
SnackBar(
backgroundColor: Colors.red,
content: new Text(e),
),
);
print(e);
}
}
and the login onTab
:
onTap: () async {
await login(
email: emailController.text,
password: passwordController.text,
);
},
Our Login Should be similar to the code below:
import 'package:auth0/constant.dart';
import 'package:auth0/signup.dart';
import 'package:flutter/material.dart';
import 'package:flutter_auth0/flutter_auth0.dart';
class Login extends StatefulWidget {
@override
_LoginState createState() => _LoginState();
}
class _LoginState extends State<Login> {
final GlobalKey<ScaffoldState> _scaffoldKey = new GlobalKey<ScaffoldState>();
final emailController = TextEditingController();
final passwordController = TextEditingController();
Auth0 auth;
bool busy = false;
@override
void initState() {
// TODO: implement initState
super.initState();
Auth0 auth = Auth0(baseUrl: 'https://$domain/', clientId: clientId);
}
login({String email, String password}) async {
try {
setState(() {
busy = true;
});
await auth.auth.passwordRealm({
'username': email,
'password': password,
'realm': 'Username-Password-Authentication'
});
setState(() {
busy = false;
});
_scaffoldKey.currentState.showSnackBar(
SnackBar(
backgroundColor: Colors.green,
content: new Text("$email has successfully logged in"),
),
);
} catch (e) {
setState(() {
busy = false;
});
_scaffoldKey.currentState.showSnackBar(
SnackBar(
backgroundColor: Colors.red,
content: new Text(e),
),
);
print(e);
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Login"),
),
body: SafeArea(
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 20.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"Login",
style: TextStyle(
fontSize: 36,
fontWeight: FontWeight.bold,
color: Colors.black,
),
),
SizedBox(height: 20),
TextField(
controller: emailController,
decoration: InputDecoration(
labelText: "Email",
border: OutlineInputBorder(
borderSide: BorderSide(color: Colors.black, width: 1.0),
),
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.black, width: 2.0),
),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.black, width: 2.0),
),
),
),
SizedBox(height: 20),
TextField(
controller: passwordController,
decoration: InputDecoration(
labelText: "Password",
border: OutlineInputBorder(
borderSide: BorderSide(color: Colors.black, width: 1.0),
),
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.black, width: 2.0),
),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.black, width: 2.0),
),
),
),
SizedBox(height: 20),
InkWell(
onTap: () async {
await login(
email: emailController.text,
password: passwordController.text,
);
},
child: Container(
height: 40,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(5),
color: Colors.blue,
),
child: Center(
child: !busy
? Text(
"Login",
style: TextStyle(
color: Colors.white,
fontSize: 20,
fontWeight: FontWeight.bold,
),
)
: CircularProgressIndicator(
strokeWidth: 2,
valueColor:
AlwaysStoppedAnimation<Color>(Colors.white),
),
),
),
),
SizedBox(height: 30),
InkWell(
onTap: () => Navigator.push(
context,
MaterialPageRoute(
builder: (context) => Signup(),
),
),
child: Row(
children: [
Text(
"You are new? ",
style: TextStyle(
fontSize: 13,
color: Colors.black,
),
),
Text(
"Create new",
style: TextStyle(
fontSize: 13,
color: Colors.blue,
),
)
],
),
)
],
),
),
),
);
}
}
Feel free to share your thoughts.