Overview
Most users give up at the registration form: a username, a password they have to remember, an e-mail code that lands in spam. With KlugAuth they tap Continue with Apple or Continue with Google and are done.
KlugAuth shows the native sign-in of each platform: Apple's sheet with Face ID / Touch ID on iOS and macOS, the Android account sheet (Credential Manager) for Google, and the system sign-in window for Google on iOS and macOS. It returns the provider's identity token together with your nonce, ready for verification on your server, plus the Apple authorization code you need to revoke the link when an account is deleted (App Store guideline 5.1.1(v)).
No Google SDK is bundled: Google sign-in on iOS and macOS uses the standard OAuth flow with PKCE in the system browser sheet, so the extension stays small.
KlugAuth runs in the current release of our apps, our proof of concept, for registration, sign-in and confirming a device logout with Apple or Google.
Features
- Self-contained: one ANE, no core library or dependency ANEs to add
- Sign in with Apple on iOS 13+, macOS 10.15+ and iPad apps on Apple silicon Macs
- Sign in with Google on Android (Credential Manager) and on iOS / macOS (system sign-in window, no Google SDK)
- Identity token, user ID, e-mail and name; Apple authorization code for refresh and revocation
- Nonce helper for replay protection (Apple carries its SHA-256, Google the raw value)
- Apple credential state check (authorized / revoked) for returning users
- Separate success, cancel and error events; cancel is reported, never an error
Supported platforms
Sign in with Apple on Android is possible with Apple's web flow and a small server page; we can provide that as part of a project. isSupported (Apple) and isGoogleSupported tell your code what the device offers.
Getting started
Add the extension to your application descriptor:
<extensions>
<extensionID>com.klug.auth.KlugAuth</extensionID>
</extensions>
For Sign in with Apple, add the entitlement (iOS: Entitlements in the descriptor; macOS: when signing):
<key>com.apple.developer.applesignin</key> <array><string>Default</string></array>
For Google, create OAuth clients in the Google Cloud console: a web client (its ID is the token audience on Android), an Android client with your package name and SHA-1, and an iOS client for iOS and macOS.
Code examples
Five complete flows, from the buttons to your server. Every call returns at once; results arrive as KlugAuthEvents. Full documentation →
import com.klug.auth.KlugAuth; import com.klug.auth.KlugAuthEvent; var auth:KlugAuth = KlugAuth.getInstance(); var nonce:String = ""; // a fresh one for every attempt appleButton.visible = auth.isSupported; // iOS 13+, macOS 10.15+, iPad apps on the Mac googleButton.visible = auth.isGoogleSupported; // Android, iOS 13+, macOS 10.15+ auth.addEventListener( KlugAuthEvent.APPLE_SUCCESS, onAppleSuccess ); auth.addEventListener( KlugAuthEvent.APPLE_CANCELED, onCanceled ); auth.addEventListener( KlugAuthEvent.APPLE_ERROR, onError ); auth.addEventListener( KlugAuthEvent.GOOGLE_SUCCESS, onGoogleSuccess ); auth.addEventListener( KlugAuthEvent.GOOGLE_CANCELED, onCanceled ); auth.addEventListener( KlugAuthEvent.GOOGLE_ERROR, onError );
function signInWithApple():void { nonce = KlugAuth.generateNonce(); // 32 random bytes as hex, used once if ( !auth.signInWithApple( nonce ) ) // false: not supported, or a sheet is already open showMessage( "Sign in with Apple is not available." ); // your app function } function onAppleSuccess( e:KlugAuthEvent ):void { // the token carries SHA-256 of the nonce: the server hashes the raw value and compares sendToServer( "apple", e.identityToken, nonce, e.fullName, e.authorizationCode ); saveAppleUserID( e.userID ); // stable for this Apple ID; your app function // e.email and the names arrive only on the FIRST authorization; // the e-mail is always inside the identity token } // your app function: the server verifies the token and signs the user in function sendToServer( provider:String, idToken:String, rawNonce:String, name:String, appleCode:String = "" ):void { var vars:URLVariables = new URLVariables(); vars.provider = provider; vars.id_token = idToken; vars.nonce = rawNonce; vars.name = name; if ( appleCode != "" ) vars.code = appleCode; // lets the server revoke the link later var req:URLRequest = new URLRequest( "https://your.server/auth" ); req.method = URLRequestMethod.POST; req.data = vars; var loader:URLLoader = new URLLoader(); loader.addEventListener( Event.COMPLETE, onServerAnswer ); // your app function loader.load( req ); }
import flash.system.Capabilities; // Android: the WEB client ID, which is the token audience on your server. // iOS and macOS: the iOS client ID, used in the system sign-in window. var googleClientId:String = Capabilities.manufacturer.indexOf( "Android" ) >= 0 ? "YOUR_WEB_CLIENT_ID.apps.googleusercontent.com" : "YOUR_IOS_CLIENT_ID.apps.googleusercontent.com"; function signInWithGoogle():void { nonce = KlugAuth.generateNonce(); // Google puts the raw value into the token if ( !auth.signInWithGoogle( googleClientId, nonce ) ) // false: no client ID, or already open showMessage( "Google sign-in could not start." ); } function onGoogleSuccess( e:KlugAuthEvent ):void { // e.userID is the account e-mail; names arrive every time sendToServer( "google", e.identityToken, nonce, e.fullName ); }
function onCanceled( e:KlugAuthEvent ):void { // the user closed the sheet: not an error, simply stay on the start screen } function onError( e:KlugAuthEvent ):void { if ( e.type == KlugAuthEvent.GOOGLE_ERROR && e.errorCode == "NO_ACCOUNT" ) showMessage( "Please add a Google account to this device first." ); // Android else showMessage( "Sign-in failed: " + e.errorMessage ); // e.errorCode for your log }
auth.addEventListener( KlugAuthEvent.APPLE_CREDENTIAL_STATE, function( e:KlugAuthEvent ):void { // e.state: authorized | revoked | notFound | transferred | unknown if ( e.state == "revoked" || e.state == "notFound" ) signOut(); // your app function: the user removed the app from their Apple ID }); var savedID:String = loadAppleUserID(); // stored after APPLE_SUCCESS; your app function if ( auth.isSupported && savedID != "" ) auth.getCredentialState( savedID ); // Apple only: iOS and macOS
API overview
| KlugAuth.getInstance() | Returns the single instance. |
| isSupported | True where Sign in with Apple is available (iOS, macOS). |
| isGoogleSupported | True where Sign in with Google is available (Android, iOS, macOS). |
| generateNonce() | Static. A fresh random nonce (32 bytes as hex); use it once and send the same value to your server. |
| signInWithApple(nonce) | Opens Apple's sign-in sheet. Returns false if it could not start (not supported, or a sign-in is already running). |
| signInWithGoogle(clientId, nonce) | Opens Google sign-in. Android: the web client ID; iOS / macOS: the iOS client ID. Returns false if it could not start. |
| getCredentialState(userID) | Asks Apple whether the user is still authorized; the answer arrives as APPLE_CREDENTIAL_STATE. iOS and macOS. |
| KlugAuthEvent | identityToken, authorizationCode, userID, email, givenName, familyName, fullName, state, errorCode, errorMessage. |
Events
| APPLE_SUCCESS | identityToken, authorizationCode, userID; email and names only on the first authorization. |
| APPLE_CANCELED | The user closed the sheet. |
| APPLE_ERROR | errorCode and errorMessage from the system. |
| APPLE_CREDENTIAL_STATE | userID and state: authorized · revoked · notFound · transferred · unknown |
| GOOGLE_SUCCESS | identityToken, userID (the account e-mail), email, givenName, familyName. |
| GOOGLE_CANCELED | The user closed the sheet. |
| GOOGLE_ERROR | errorCode and errorMessage; on Android NO_ACCOUNT when the device has no Google account. |
Buy KlugAuth
A yearly licence for one AIR application, with all updates for 12 months. After payment you receive the extension, the ActionScript library and the documentation by e-mail, usually within one business day. Licence and terms
- Licence for one AIR application
- All updates for 12 months
- Answer by e-mail within 7 days
- Licence for one AIR application
- All updates for 12 months
- Answer by e-mail within 48 hours
Requirements
| AIR SDK | 51.x (HARMAN) |
| iOS | iOS 13 or later |
| Android | Android 6 or later, Google Play services |
| macOS | macOS 10.15 or later |
| Apple | Sign in with Apple capability on your App ID |
| OAuth clients in the Google Cloud console |