This tutorial shows how to use PlusAuth with Flutter Application. If you do not have a PlusAuth account, register from here.
This tutorial follows the plusauth-flutter-starter sample project on Github. You can download and follow the tutorial via the sample project.
Create PlusAuth Client
After you sign up or log in to PlusAuth, you need to create a client to get the necessary configuration keys in the dashboard. Go to Clients and create a client with the type of Native Application
Configure Client
Get Client Properties
You will need your Client Id
for interacting with PlusAuth. You can retrieve them from the created client's details.
Configure Redirect and Logout URIs
When PlusAuth authenticates a user, it needs a URI to redirect back. That URI must be in your client's Redirect URI
list. If your application uses a redirect URI that is not white-listed in your PlusAuth Client, you will receive an error.
The same thing applies to the logout URIs. After the user logs out, you need a URI to be redirected.
If you are following the sample project, the Redirect URL you need to add to the Redirect URIs field is com.plusauth.flutterexample:/oauthredirect/login
. The Logout URL you need to add to the Post Logout Redirect URIs field is com.plusauth.flutterexample:/
.
Configure Flutter to use PlusAuth
Create a Flutter application or download the sample project from the link on the top of the page.
Add Dependencies
To get started, install the following dependencies.
- flutter_appauth - a Flutter bridge for AppAuth used authenticating and authorizing users
- http - a composable library for making HTTP requests.
- flutter_secure_storage - a Flutter plugin to store data in secure storage
# installation with flutter pubflutter pub add flutter_appauthflutter pub add httpflutter pub add flutter_secure_storage
Android Setup
Add redirect scheme to your Android app module's build.gradle
file.
...android { ... defaultConfig { ... manifestPlaceholders += [ 'appAuthRedirectScheme': '<your_custom_scheme>' // ex: com.plusauth.flutterexample ] }}
Add the following queries to your AndroidManifest.xml
file a level underneath the <manifest>
element.
<queries> <intent> <action android:name="android.intent.action.VIEW" /> <category android:name="android.intent.category.BROWSABLE" /> <data android:scheme="https" /> </intent> <intent> <action android:name="android.intent.action.VIEW" /> <category android:name="android.intent.category.APP_BROWSER" /> <data android:scheme="https" /> </intent></queries>
iOS Setup
Go to the Info.plist
for your iOS app and add a redirect scheme like the following.
<key>CFBundleURLSchemes</key><array> <string>your_custom_scheme</string> <!-- ex: com.plusauth.flutterexample --></array>
Configure FlutterAppAuth Instance
We need to initialize our Flutter AppAuth library to handle authentication-related operations. Create a new FlutterAppAuth
instance in main.dart
under lib
folder.
// lib/main.dart
class _MyHomePageState extends State<MyHomePage> {
// ...
final String _clientId = '<YOUR_CLIENT_ID>'; final String _redirectUrl = 'com.plusauth.flutterexample:/oauthredirect/login'; final String _issuer = 'https://<YOUR_TENANT_ID>.plusauth.com'; final String _postLogoutRedirectUrl = 'com.plusauth.flutterexample:/'; final List<String> _scopes = <String>['openid', 'profile', 'email', 'offline_access'];
// Create FlutterAppAuth instance final FlutterAppAuth _appAuth = FlutterAppAuth();
// Create FlutterSecureStorage instance to store refresh_token securely final FlutterSecureStorage _secureStorage = const FlutterSecureStorage();
// ...}
Replace _clientId
value with your Client Id
defined in the Configure Client section. Also change the _issuer
value with your Tenant Id
.
If you set your custom scheme other than com.plusauth.flutterexample
, replace the _redirectUrl
and _postLogoutRedirectUrl
values accordingly.
Implement login, user profile, and logout
Add the following sections to your main.dart
file under the lib
folder. We will store the retrieved refresh_token
in secure storage to exchange with new tokens.
Add Login
We will be using the authorizeAndExchangeCode
method to authenticate the user. The application redirects you to the PlusAuth
login page using the browser.
Add the following section to your main.dart
file to start an authentication process.
// lib/main.dart
Future<void> _signIn() async { try { _setLoading(true); final AuthorizationTokenResponse? result = await _appAuth.authorizeAndExchangeCode( AuthorizationTokenRequest( _clientId, _redirectUrl, issuer: _issuer, scopes: _scopes), ); if (result != null) { _processAuthTokenResponse(result); // process and extract tokens from response } } catch (_) { _setLoading(false); }}
After successful authentication, extract the tokens from response data. We will be storing refresh_token
in local storage to retrieve new tokens later.
// lib/main.dart
// Process login responsevoid _processAuthTokenResponse(AuthorizationTokenResponse response) { // Save refresh token to storage to exchange with new one _secureStorage.write(key: 'refresh_token', value: response.refreshToken); setState(() { _isLoggedIn = true; _accessToken = response.accessToken!; _idToken = response.idToken!; _refreshToken = response.refreshToken!; }); _fetchUserInfo();}
Add Logout
Add the following section to log out from the application and PlusAuth:
// lib/main.dart
Future<void> _singOut() async { try { _setLoading(true); // User Logout await _appAuth.endSession(EndSessionRequest( idTokenHint: _idToken, postLogoutRedirectUrl: _postLogoutRedirectUrl, issuer: _issuer)); _clearSessionInfo(); } catch (_) { _setLoading(false); }}
Clear all the tokens and storage after the successful logout process.
// lib/main.dart
void _clearSessionInfo() { _secureStorage.delete(key: 'refresh_token'); setState(() { _isLoggedIn = false; _userName = null; _userInfo = null; _accessToken = null; _idToken = null; _refreshToken = null; });}
Refreshing Tokens
Add the following section to renew tokens using refresh_token
that we stored in local storage.
// lib/main.dart
Future<void> _refreshAuthToken() async { try { _setLoading(true); // Get new token using refresh token final TokenResponse? result = await _appAuth.token(TokenRequest( _clientId, _redirectUrl, refreshToken: _refreshToken, issuer: _issuer, scopes: _scopes)); _processTokenResponse(result); } catch (_) { _clearSessionInfo(); // Clear all the tokens if an error occurs } finally { _setLoading(false); }}
Extract new tokens from TokenResponse
and store renewed Refresh Token
in local storage.
//lib/main.dart
// Process refresh token exchange responsevoid _processTokenResponse(TokenResponse? response) { _secureStorage.write(key: 'refresh_token', value: response!.refreshToken); setState(() { _isLoggedIn = true; _accessToken = response.accessToken!; _idToken = response.idToken!; _refreshToken = response.refreshToken!; }); _fetchUserInfo();}
Add View
Finally, add the following section to your Widget
to interact with the user.
//lib/main.dart
// ...
body: Center( child: Padding( padding: const EdgeInsets.all(12), child: Column( mainAxisAlignment: MainAxisAlignment.start, children: <Widget>[ Visibility( visible: _isLoading, child: const LinearProgressIndicator(), // Loading Bar ), Text('Welcome to PlusAuth Flutter Demo!', style: TextStyle( fontSize: 21.0 ) ), Text('Username: ${_userName ?? '-'}', style: const TextStyle( fontSize: 18.0 ) ), Visibility( child: ElevatedButton( child: const Text('Login'), onPressed: _signIn, ), visible: !_isLoggedIn, ), Visibility( child: ElevatedButton( child: const Text('Logout'), onPressed: _singOut, ), visible: _isLoggedIn, ), Text(_userInfo ?? '', style: const TextStyle( fontSize: 16.0 ) ), ], ), )),
// ...
See it in action
That's it. Start your app and point to your device or emulator. Follow the Log In link to log in or sign up to your PlusAuth tenant. After you click the Login
button, the browser launches and shows the PlusAuth Login page. Upon successful login or signup, you should be redirected back to the application.