flutter_appauth 0.1.1 flutter_appauth: ^0.1.1 copied to clipboard
This plugin provides an abstraction around the Android and iOS AppAuth SDKs so it can be used to communicate with OAuth 2.0 and OpenID Connect providers
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'package:flutter_appauth/flutter_appauth.dart';
void main() => runApp(MyApp());
class MyApp extends StatefulWidget {
@override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
bool _isBusy = false;
FlutterAppAuth _appAuth = FlutterAppAuth();
String _codeVerifier;
String _authorizationCode;
String _refreshToken;
String _accessToken;
TextEditingController _authorizationCodeTextController =
TextEditingController();
TextEditingController _accessTokenTextController = TextEditingController();
TextEditingController _accessTokenExpirationTextController =
TextEditingController();
TextEditingController _idTokenTextController = TextEditingController();
TextEditingController _refreshTokenTextController = TextEditingController();
String _userInfo = '';
String _clientId = 'native.code';
String _redirectUrl = 'io.identityserver.demo:/oauthredirect';
String _issuer = 'https://demo.identityserver.io';
String _discoveryUrl =
'https://demo.identityserver.io/.well-known/openid-configuration';
List<String> _scopes = [
'openid',
'profile',
'email',
'offline_access',
'api'
];
AuthorizationServiceConfiguration _serviceConfiguration =
AuthorizationServiceConfiguration(
'https://demo.identityserver.io/connect/authorize',
'https://demo.identityserver.io/connect/token');
@override
void initState() {
super.initState();
}
Future _refresh() async {
setBusyState();
var result = await _appAuth.token(TokenRequest(_clientId, _redirectUrl,
refreshToken: _refreshToken,
discoveryUrl: _discoveryUrl,
scopes: _scopes));
_processTokenResponse(result);
await _testApi(result);
}
Future _exchangeCode() async {
setBusyState();
var result = await _appAuth.token(TokenRequest(_clientId, _redirectUrl,
authorizationCode: _authorizationCode,
discoveryUrl: _discoveryUrl,
codeVerifier: _codeVerifier,
scopes: _scopes));
_processTokenResponse(result);
await _testApi(result);
}
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: const Text('Plugin example app'),
),
body: SingleChildScrollView(
child: Column(
children: <Widget>[
Visibility(
visible: _isBusy,
child: LinearProgressIndicator(),
),
RaisedButton(
child: Text('Sign in with no code exchange'),
onPressed: () async {
setBusyState();
// use the discovery endpoint to find the configuration
var result = await _appAuth.authorize(
AuthorizationTokenRequest(
_clientId,
_redirectUrl,
discoveryUrl: _discoveryUrl,
scopes: _scopes,
),
);
// or just use the issuer
// var result = await _appAuth.authorize(
// AuthorizationTokenRequest(
// _clientId,
// _redirectUrl,
// issuer: _issuer,
// scopes: _scopes,
// ),
// );
if (result != null) {
_processAuthResponse(result);
}
},
),
RaisedButton(
child: Text('Exchange code'),
onPressed: _authorizationCode != null ? _exchangeCode : null,
),
RaisedButton(
child: Text('Sign in with auto code exchange'),
onPressed: () async {
setBusyState();
// show that we can also explicitly specify the endpoints rather than getting from the details from the discovery document
var result = await _appAuth.authorizeAndExchangeCode(
AuthorizationTokenRequest(
_clientId,
_redirectUrl,
serviceConfiguration: _serviceConfiguration,
scopes: _scopes,
),
);
if (result != null) {
_processAuthTokenResponse(result);
await _testApi(result);
}
},
),
RaisedButton(
child: Text('Refresh token'),
onPressed: _refreshToken != null ? _refresh : null,
),
Text('authorization code'),
TextField(
controller: _authorizationCodeTextController,
),
Text('access token'),
TextField(
controller: _accessTokenTextController,
),
Text('access token expiration'),
TextField(
controller: _accessTokenExpirationTextController,
),
Text('id token'),
TextField(
controller: _idTokenTextController,
),
Text('refresh token'),
TextField(
controller: _refreshTokenTextController,
),
Text('test api results'),
Text(_userInfo),
],
),
),
),
);
}
void setBusyState() {
setState(() {
_isBusy = true;
});
}
void _processAuthTokenResponse(AuthorizationTokenResponse response) {
setState(() {
_accessToken = _accessTokenTextController.text = response.accessToken;
_idTokenTextController.text = response.idToken;
_refreshToken = _refreshTokenTextController.text = response.refreshToken;
_accessTokenExpirationTextController.text =
response.accessTokenExpirationDateTime?.toIso8601String();
});
}
void _processAuthResponse(AuthorizationResponse response) {
setState(() {
// save the code verifier as it must be used when exchanging the token
_codeVerifier = response.codeVerifier;
_authorizationCode =
_authorizationCodeTextController.text = response.authorizationCode;
_isBusy = false;
});
}
void _processTokenResponse(TokenResponse response) {
setState(() {
_accessToken = _accessTokenTextController.text = response.accessToken;
_idTokenTextController.text = response.idToken;
_refreshToken = _refreshTokenTextController.text = response.refreshToken;
_accessTokenExpirationTextController.text =
response.accessTokenExpirationDateTime?.toIso8601String();
});
}
Future _testApi(TokenResponse response) async {
var httpResponse = await http.get('https://demo.identityserver.io/api/test',
headers: {'Authorization': 'Bearer $_accessToken'});
setState(() {
_userInfo = httpResponse.statusCode == 200 ? httpResponse.body : '';
_isBusy = false;
});
}
}