diff --git a/packages/gotrue/lib/src/gotrue_client.dart b/packages/gotrue/lib/src/gotrue_client.dart index aa9ab6f6..904b327f 100644 --- a/packages/gotrue/lib/src/gotrue_client.dart +++ b/packages/gotrue/lib/src/gotrue_client.dart @@ -514,6 +514,59 @@ class GoTrueClient { return authResponse; } + /// Obtains a URL to perform a single-sign on using an enterprise Identity + /// Provider. The redirect URL is implementation and SSO protocol specific. + /// + /// You can use it by providing a SSO domain. Typically you can extract this + /// domain by asking users for their email address. If this domain is + /// registered on the Auth instance the redirect will use that organization's + /// currently active SSO Identity Provider for the login. + /// + /// If you have built an organization-specific login page, you can use the + /// organization's SSO Identity Provider UUID directly instead. + Future getSSOSignInUrl({ + String? providerId, + String? domain, + String? redirectTo, + String? captchaToken, + }) async { + assert( + providerId != null || domain != null, + 'providerId or domain has to be provided.', + ); + + _removeSession(); + String? codeChallenge; + String? codeChallengeMethod; + if (_flowType == AuthFlowType.pkce) { + assert(_asyncStorage != null, + 'You need to provide asyncStorage to perform pkce flow.'); + final codeVerifier = generatePKCEVerifier(); + await _asyncStorage!.setItem( + key: '${Constants.defaultStorageKey}-code-verifier', + value: codeVerifier); + codeChallenge = generatePKCEChallenge(codeVerifier); + codeChallengeMethod = codeVerifier == codeChallenge ? 'plain' : 's256'; + } + + final res = await _fetch.request('$_url/sso', RequestMethodType.post, + options: GotrueRequestOptions( + body: { + if (providerId != null) 'provider_id': providerId, + if (domain != null) 'domain': domain, + if (redirectTo != null) 'redirect_to': redirectTo, + if (captchaToken != null) + 'gotrue_meta_security': {'captcha_token': captchaToken}, + 'skip_http_redirect': true, + 'code_challenge': codeChallenge, + 'code_challenge_method': codeChallengeMethod, + }, + headers: _headers, + )); + + return res['url'] as String; + } + /// Force refreshes the session including the user data in case it was updated /// in a different session. Future refreshSession() async { diff --git a/packages/supabase_flutter/lib/src/supabase_auth.dart b/packages/supabase_flutter/lib/src/supabase_auth.dart index 2cc371e6..45f915c4 100644 --- a/packages/supabase_flutter/lib/src/supabase_auth.dart +++ b/packages/supabase_flutter/lib/src/supabase_auth.dart @@ -294,6 +294,47 @@ extension GoTrueClientSignInProvider on GoTrueClient { return result; } + /// Attempts a single-sign on using an enterprise Identity Provider. A + /// successful SSO attempt will redirect the current page to the identity + /// provider authorization page. The redirect URL is implementation and SSO + /// protocol specific. + /// + /// You can use it by providing a SSO domain. Typically you can extract this + /// domain by asking users for their email address. If this domain is + /// registered on the Auth instance the redirect will use that organization's + /// currently active SSO Identity Provider for the login. + /// + /// If you have built an organization-specific login page, you can use the + /// organization's SSO Identity Provider UUID directly instead. + /// + /// Returns true if the URL was launched successfully, otherwise either returns + /// false or throws a [PlatformException] depending on the launchUrl failure. + /// + /// ```dart + /// await supabase.auth.signInWithSSO( + /// domain: 'company.com', + /// ); + /// ``` + Future signInWithSSO({ + String? providerId, + String? domain, + String? redirectTo, + String? captchaToken, + LaunchMode launchMode = LaunchMode.platformDefault, + }) async { + final ssoUrl = await getSSOSignInUrl( + providerId: providerId, + domain: domain, + redirectTo: redirectTo, + captchaToken: captchaToken, + ); + return await launchUrl( + Uri.parse(ssoUrl), + mode: launchMode, + webOnlyWindowName: '_self', + ); + } + String generateRawNonce() { final random = Random.secure(); return base64Url.encode(List.generate(16, (_) => random.nextInt(256)));