Back

Link Anonymous Account with OAuth2 logins

  • 0
  • Users
  • Flutter
  • Self Hosted
  • REST API
canbi
12 Dec, 2023, 19:59

I am currently using the REST API (1.4.x). I have implemented Sign in with Apple and Sign in with Google. On the Anonymous Login Docs Page, it says "If a user later creates an account, their information will be inherited by the newly created account."

How can we manage this in the REST API? Is this handled by Appwrite itself?

TL;DR
The user is asking for help with linking an anonymous account with OAuth2 logins. They tried setting a cookie header for anonymous linking but it didn't work. They also found some information about FlutterWebAuth2 not supporting headers for all platforms. They are using the REST API and want to know how to manage the process of linking an anonymous account with OAuth2 logins in the REST API. Solution: It seems that the linking of an anonymous account with OAuth2 logins is handled by Appwrite itself. If a user creates an account after signing in with OAuth2, their information will be inherited by the newly created account. An
canbi
12 Dec, 2023, 20:00

I am putting working REST API OAuth integrations as an example.

TypeScript
class SignInWithAppleButton extends HookConsumerWidget {
  const SignInWithAppleButton({super.key});

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    return ElevatedButton(
      onPressed: () async {
        const baseUrl = AppwriteConstants.appleOAuthUrl;
        final queryParams = {
          'project': AppwriteConstants.projectId,
          'scope': 'email name',
        };
        final fullUrl = Uri.parse(baseUrl).replace(queryParameters: queryParams);

        await FlutterWebAuth2.authenticate(
          url: fullUrl.toString(),
          callbackUrlScheme: AppwriteConstants.oAuthCallbackScheme,
          options: const FlutterWebAuth2Options(preferEphemeral: true),
        ).then((value) async {
          final url = Uri.parse(value);
          final secret = url.queryParameters['secret'];
          if (secret == null) throw Exception('Invalid response from Apple');

          await ref.read(localCacheHandlerProvider).setSession(secret);
        }).onError((error, stackTrace) {});
      },
      child: const Text('Sign in With Apple'),
    );
  }
}

//oAuthCallbackScheme = 'appwrite-callback-<PROJECT_ID>';
//appleOAuthUrl = '<API_ENDPOINT>/account/sessions/oauth2/apple';

// Google Sign In similar as Apple
Drake
12 Dec, 2023, 23:46

If i recall correctly, if the user already has an anonymous session and then they create an oauth session, the account should turn into a regular account

canbi
13 Dec, 2023, 13:46

I will check but it will take time because I am writing my app from scratch. I will post the result here

canbi
16 Dec, 2023, 11:26

I tried to link the anonymous account with OAuth but it didn't work. Here are the steps I followed:

  • Anonymous account created
  • I signed in with Apple

After these steps in the Appwrite Auth panel, I have 2 different accounts and anonymous is still showing as unverified. No link has been made.

I think this is current issue related to this: https://github.com/appwrite/sdk-for-flutter/issues/30

Drake
17 Dec, 2023, 02:01

Wait...this is in flutter?

canbi
17 Dec, 2023, 06:39

I’m using Flutter with Rest API right now. I haven’t tried with Appwrite Flutter package. In rest api, maybe I am missing something.

Drake
17 Dec, 2023, 08:06

How are you doing oauth with the rest api?

canbi
17 Dec, 2023, 09:47
TypeScript
ElevatedButton(
    onPressed: () async {
      const baseUrl = '${AppwriteConstants.endPoint}/account/sessions/oauth2/apple';
      final queryParams = {'project': AppwriteConstants.projectId, 'scope': 'email name'};
      final fullUrl = Uri.parse(baseUrl).replace(queryParameters: queryParams);

      try {
        final responseUrl = await FlutterWebAuth2.authenticate(
          url: fullUrl.toString(),
          callbackUrlScheme: 'appwrite-callback-${AppwriteConstants.projectId}',
          options: const FlutterWebAuth2Options(preferEphemeral: true),
        );

        final url = Uri.parse(responseUrl);
        final secret = url.queryParameters['secret'];
        if (secret == null) throw Exception('Invalid response from OAuth');
        onSuccessCallback(secret);
      } on PlatformException catch (e, st) {
        if (e.code == 'CANCELED') return;
        onFailureCallback(e, st);
      } catch (e, st) {
        onFailureCallback(e, st);
      }
    },
    child: const Text('Sign in With Apple'),
);

I think it's similar to how OAuth works in Appwrite. As you can see, there is no cookie passing or anything like that. There's just the projectId passed to OAuth flow.

I did it by taking an example from the code here: https://github.com/appwrite/sdk-for-flutter/blob/cab0a1360fe3c70c27d00154ccf2d3dd6b56e813/lib/src/client_io.dart#L318

Drake
17 Dec, 2023, 17:15

Why aren't you using the flutter sdk?

Anyways, this would be the problem. Because the session (cookie) isn't passed Appwrite doesn't know to convert the anonymous session to a regular user

canbi
17 Dec, 2023, 20:21

I am using REST Api because I am experimenting offline data sync feature with flutter_data package.

As far as I understand, FlutterWebAuth2 package not allow us to give http headers (as discussed in given issue). I am going to try with regular web view and give cookie header. I will share my work if it works.

My findings:

Drake
17 Dec, 2023, 20:32

I can't remember why I decided not to use flutter_data...I ended up using the brick package

Drake
17 Dec, 2023, 20:34

I think I tried making a custom adapter but it wasn't easy...

Drake
17 Dec, 2023, 20:37

Hmm maybe things have changed since I looked at that package

Drake
17 Dec, 2023, 20:40

But yes... we've talked about no longer using the web auth 2 package so that we can fully control the tab/window that's opened and we can inject the session if there is one

canbi
17 Dec, 2023, 22:29

flutter_data is very confusing and has very steep learning curve but i am still trying to adapt it, maybe i will use brick package if I can not figure out flutter_data.

I have implemented Apple sign in flow with Webview Flutter package and it works as intended but still could not figure out session part of the linking anonymous account.

How should I set cookie header for anonymous linking?

I have tried to this but it is not working:

TypeScript
... // Webview flutter implementation. I am not sharing it because still not working with linking.
Future<void> _signInWithApple() async {
    const baseUrl = AppwriteConstants.appleOAuthUrl;
    final queryParams = {'project': AppwriteConstants.projectId, 'scope': 'email name'};
    final fullUrl = Uri.parse(baseUrl).replace(queryParameters: queryParams);
    
    // TODO() which name and domain should be use here?
    await WebViewCookieManager().setCookie(
      const WebViewCookie(name: AppwriteConstants.sessionKey, value: '<SESSION>', domain: '<DOMAIN>'),
    );

    await _controller.loadRequest(fullUrl);
  }
...
Drake
17 Dec, 2023, 23:02
Reply

Reply to this thread by joining our Discord

Reply on Discord

Need support?

Join our Discord

Get community support by joining our Discord server.

Join Discord

Get premium support

Join Appwrite Pro and get email support from our team.

Learn more