piano_id 1.0.8
piano_id: ^1.0.8 copied to clipboard
Piano ID Flutter SDK.
Piano ID SDK for Flutter #
Piano ID Flutter SDK provides user authentication via Piano ID, including sign-in/sign-up UI, token management, and user info retrieval.
Installation #
Add the dependency to your pubspec.yaml:
dependencies:
piano_id: ^1.0.8
piano_id depends on piano_common, so you need a Piano instance first.
import 'package:piano_common/piano_common.dart';
import 'package:piano_id/piano_id.dart';
final piano = await Piano.init(
endpoint: PianoEndpoint.production,
aid: '<AID>',
);
piano.id() is a Piano ID client of that instance — a new one every call, since a client holds nothing of its own. What the calls share, such as the Piano ID deployment host, belongs to the instance, so it is looked up once however many clients you ask for. Nothing has to be configured; pass a PianoIDConfiguration to Piano.init when you want to configure Piano ID, which today means offering OAuth providers on the sign-in screen.
Sign In #
Show the Piano ID authentication screen. The SDK presents a platform-appropriate modal (Cupertino on iOS, Material bottom sheet on Android) with an embedded WebView.
final token = await piano.id().signIn(context: context);
if (token != null) {
print('Access token: ${token.accessToken}');
print('Refresh token: ${token.refreshToken}');
}
Sign Up #
Open the registration screen instead of login:
final token = await piano.id().signIn(
context: context,
signUp: true,
);
Disable Sign Up #
Hide the sign-up option on the login screen:
final token = await piano.id().signIn(
context: context,
signUpEnabled: false,
);
Custom Events #
Listen for custom events from the Piano ID form:
final token = await piano.id().signIn(
context: context,
onCustomEvent: (event) {
print('Custom event: $event');
},
);
Localization #
The sign-in screen is shown in the language configured on the Piano instance, which defaults to en_US:
final piano = await Piano.init(
endpoint: PianoEndpoint.production,
aid: '<AID>',
language: 'fr_FR',
);
final token = await piano.id().signIn(context: context);
Social Sign In #
The sign-in screen can offer OAuth providers — Google, Facebook, … — next to Piano ID's own login. A provider is an implementation of PianoIDOAuthProvider listed in the configuration:
final piano = await Piano.init(
endpoint: PianoEndpoint.production,
aid: '<AID>',
configurations: [
PianoIDConfiguration(providers: [PianoIDGoogleOAuthProvider()]),
],
);
// The screen now shows a Google button as well; picking it runs the provider
// and finishes the sign-in with the token it returns.
final token = await piano.id().signIn(context: context);
Only a provider listed here is offered by the screen, because only your application knows which provider packages it ships. Google sign-in is available as piano_id_google and Facebook sign-in as piano_id_facebook, which provide PianoIDGoogleOAuthProvider and PianoIDFacebookOAuthProvider; writing your own provider means implementing two members:
class MyOAuthProvider extends PianoIDOAuthProvider {
@override
String get name => 'google';
@override
Future<PianoIDOAuthResult> login({
required BuildContext context,
required String clientId,
}) async {
final token = await signInWithMyProvider(clientId);
if (token == null) {
// The user dismissed the provider: the sign-in screen stays open.
return const PianoIDOAuthCancelledResult();
}
return PianoIDOAuthSuccessResult(provider: name, token: token);
}
}
name is the provider as Piano ID knows it (google, facebook, …) and is matched ignoring case. clientId is the OAuth client id Piano ID supplies for that provider. Anything thrown from login fails the sign-in, so signIn reports it to the caller.
PianoIDOAuthCancelledResult takes an optional description, which the sign-in screen writes to the log with the cancellation. Pass whatever the provider said about it where a provider cannot tell a dismissal apart from a failure, so a cancellation nobody made can still be recognized.
Sign Out #
Invalidate a user's access token:
await piano.id().signOut(accessToken: token.accessToken);
Refresh Token #
Exchange a refresh token for a new token pair:
final newToken = await piano.id().refreshToken(
refreshToken: token.refreshToken,
);
print('New access token: ${newToken.accessToken}');
User Info #
Fetch the authenticated user's profile:
final user = await piano.id().userInfo(
accessToken: token.accessToken,
);
print('${user.firstName} ${user.lastName}');
print('Email: ${user.email}');
print('UID: ${user.uid}');
Optionally pass a form name:
final user = await piano.id().userInfo(
accessToken: token.accessToken,
formName: 'registration',
);
for (final field in user.customFields) {
print('${field.fieldName}: ${field.value}');
}
Form Info #
Check whether a user has filled all custom fields for a form:
final form = await piano.id().formInfo(
accessToken: token.accessToken,
formName: 'registration',
);
if (!form.hasAllCustomFieldValuesFilled) {
// Prompt the user to complete their profile
}
Error Handling #
All methods throw exception on failure:
try {
await piano.id().signOut(accessToken: token.accessToken);
} on PianoException catch (e) {
print('Piano error: ${e.message}');
} catch (e) {
print('Piano error: ${e}');
}