Skip to content

Instantly share code, notes, and snippets.

@BerndWessels
Created March 4, 2019 21:03
Show Gist options
  • Save BerndWessels/fe85f558fe2a2ead7e94fef4babe9ead to your computer and use it in GitHub Desktop.
Save BerndWessels/fe85f558fe2a2ead7e94fef4babe9ead to your computer and use it in GitHub Desktop.
Flutter AWS Cognito Federated Identities Login
import 'package:amazon_cognito_identity_dart/cognito.dart';
import 'package:amazon_cognito_identity_dart/sig_v4.dart';
import 'package:http/http.dart' as http;
class Credentials {
final CognitoCredentials _cognitoCredentials;
final String _token;
final String _authenticator;
Credentials(String identityPoolId, String userPoolId, String clientId, this._token, [this._authenticator])
: _cognitoCredentials = new CognitoCredentials(identityPoolId, new CognitoUserPool(userPoolId, clientId));
Future<CognitoCredentials> get cognitoCredentials async {
await _cognitoCredentials.getAwsCredentials(_token, _authenticator);
return _cognitoCredentials;
}
}
class Api {
final String endpoint;
final String path;
final String region;
final Credentials credentials;
Api(this.endpoint, this.path, this.region, this.credentials);
post(Map body) async {
CognitoCredentials cognitoCredentials = await credentials.cognitoCredentials;
final awsSigV4Client = new AwsSigV4Client(
cognitoCredentials.accessKeyId,
cognitoCredentials.secretAccessKey,
endpoint,
sessionToken: cognitoCredentials.sessionToken,
region: region,
);
final signedRequest = new SigV4Request(
awsSigV4Client,
method: 'POST',
path: path,
// headers: new Map<String, String>.from({'header-1': 'one', 'header-2': 'two'}),
// queryParams: new Map<String, String>.from({'tracking': 'x123'}),
body: new Map<String, dynamic>.from(body),
);
http.Response response;
response = await http.post(signedRequest.url, headers: signedRequest.headers, body: signedRequest.body);
return response;
}
}
import 'package:flutter_facebook_login/flutter_facebook_login.dart';
Future<FacebookLoginResult> signInWithFacebook() async {
final facebookLogin = FacebookLogin();
final facebookLoginResult = await facebookLogin.logInWithReadPermissions(['email']);
return facebookLoginResult;
}
import 'package:google_sign_in/google_sign_in.dart';
Future<GoogleSignInAuthentication> signInWithGoogle() async {
final GoogleSignIn googleSignIn = GoogleSignIn(scopes: ['email']);
final GoogleSignInAccount googleSignInAccount = await googleSignIn.signIn();
GoogleSignInAuthentication googleSignInAuthentication = await googleSignInAccount.authentication;
return googleSignInAuthentication;
}
import 'package:flutter/material.dart';
import 'package:flutter_app/aws.dart';
import 'package:flutter_app/facebook.dart';
import 'package:flutter_app/google.dart';
import 'package:flutter_app/secret.dart';
void main() => runApp(MyApp());
signInFacebook() async {
final facebookLoginResult = await signInWithFacebook();
final credentials = new Credentials(
cognitoIdentityPoolId,
cognitoUserPoolId,
cognitoClientId,
facebookLoginResult.accessToken.token,
'graph.facebook.com',
);
final api = Api(apiEndpointUrl, '/flutter', 'ap-southeast-2', credentials);
final result = await api.post({});
print(result.body);
}
signInGoogle() async {
final googleSignInAuthentication = await signInWithGoogle();
final credentials = new Credentials(
cognitoIdentityPoolId,
cognitoUserPoolId,
cognitoClientId,
googleSignInAuthentication.idToken,
'accounts.google.com',
);
final api = Api(apiEndpointUrl, '/flutter', 'ap-southeast-2', credentials);
final result = await api.post({});
print(result.body);
}
@itskgore
Copy link

what is graph.com.facebook is that the default one I should use?

@itskgore
Copy link

statusCode: 400, code: NotAuthorizedException, name: NotAuthorizedException, message: Invalid login token. Issuer doesn't match providerName (I am getting this error can you help out)

@aldiazve
Copy link

Hi! I'm having the same response:

CognitoClientException{statusCode: 400, code: NotAuthorizedException, name: NotAuthorizedException, message: Invalid login token. Issuer doesn't match providerName}

Any help?

@hoonblizz
Copy link

It works okay for me.
I just set up my own API Gateway and tested with it.
My question is, how do we restrict access by token_id?
I mean, if I don't set anything, API will work whether I sign in by google or not (free API for all).
Any help will be great. Thanks!

@abhi3011
Copy link

Alejandro Díaz Vecchio, Any luck around your issue? I'm getting the same exception.

@aldiazve
Copy link

Alejandro Díaz Vecchio, Any luck around your issue? I'm getting the same exception.

Yes, we where trying to fix this for at least 5 days :C. I ended up switching the whole project to Firebase.

@abhi3011
Copy link

Okay cool, thanks for the reply, in my case have to stick to AWS due to RDS requirements, will try to work something out.

@alextarrago
Copy link

@abhi3011 did you find any workaround?

@abhi3011
Copy link

abhi3011 commented Feb 23, 2022 via email

@alextarrago
Copy link

alextarrago commented Feb 23, 2022

How did you pass the Firebase token to Cognito? Thanks for the reply man!

@abhi3011
Copy link

abhi3011 commented Feb 23, 2022 via email

@alextarrago
Copy link

It would help our team a lot on knowing that answer🙏🏼 Thanks!

@akotorri
Copy link

akotorri commented Jun 17, 2022

I don't remember that now, I soon left the project, but I will try to ask the guys tomorrow and let you know

On Thu, Feb 24, 2022, 12:58 AM Alex Tarragó @.> wrote: @.* commented on this gist. ------------------------------ How did you pass the Firebase token to Cognito? — Reply to this email directly, view it on GitHub https://gist.github.com/fe85f558fe2a2ead7e94fef4babe9ead#gistcomment-4076137, or unsubscribe https://github.com/notifications/unsubscribe-auth/ACOKWWRV2ZQUCMZ6D53JULDU4UYNTANCNFSM4LNEUONQ . Triage notifications on the go with GitHub Mobile for iOS https://apps.apple.com/app/apple-store/id1477376905?ct=notification-email&mt=8&pt=524675 or Android https://play.google.com/store/apps/details?id=com.github.android&referrer=utm_campaign%3Dnotification-email%26utm_medium%3Demail%26utm_source%3Dgithub. You are receiving this because you were mentioned.Message ID: @.***>

Any updates on this matter because I'm stuck on the same issue as well, because In my case I'm using this package: https://pub.dev/packages/amazon_cognito_identity_dart_2 and here it kinda gives a solution (Use case 19) but I'm stuck on it because for some reason it doesn’t work for me

@alextarrago
Copy link

Hi @akotorri , none of the solutions worked for us. We ended up implementin a webview solution that returned the required credential (nothing elegant, but functional). If you need more info, don't hesitate to contact me over email ([email protected])

@akotorri
Copy link

Hi @akotorri , none of the solutions worked for us. We ended up implementin a webview solution that returned the required credential (nothing elegant, but functional). If you need more info, don't hesitate to contact me over email ([email protected])

Hi @alextarrago I figured that I will have to implement a webview of some sort, and so I ended up going that path and found the https://pub.dev/packages/amazon_cognito_identity_dart_2 this package and in its doc had a "Use Case 19" for google auth implemented with a webview but for some reasons it just doesn’t work for me, so I would love it if you could share with me how you guys implemented it with webview cuz it would save me a ton of time

@akotorri
Copy link

Hi @akotorri , none of the solutions worked for us. We ended up implementin a webview solution that returned the required credential (nothing elegant, but functional). If you need more info, don't hesitate to contact me over email ([email protected])

Can you provide some sample code on how you guys did the google auth with a webview? P.S. I'm not looking for anything pretty just functional.

@alextarrago
Copy link

Launching a WebView with the Web Authentication process ...

ssoLogin(String method) async {
    String uri =
        "${dotenv.env["COGNITO_POOL_URL"]}oauth2/authorize?redirect_uri=app://callback&response_type=code&client_id=${dotenv.env["COGNITO_CLIENT_ID"]}&identity_provider=$method&scope=phone%20email%20openid%20profile%20aws.cognito.signin.user.admin";
    await launch(uri, forceSafariVC: false);
  }

Where method is facebook, google or signInWithApple. The redirect_uri is the key here, once the web calls the redirect_uri, we retrieve the code as follows.

void _handleIncomingLinks() {
    uriLinkStream.listen((Uri? uri) async {
      if (uri!.queryParameters["code"] != null) {
        ssoWithAuthorizationCode(uri.queryParameters["code"]!);
      }
    }, onError: (Object err) {
      print(err);
    });
  }

and then...

ssoWithAuthorizationCode(String authorizationCode) async {
    final uri = Uri.parse(
        "${dotenv.env["COGNITO_POOL_URL"]}oauth2/token?grant_type=authorization_code&client_id=${dotenv.env["COGNITO_CLIENT_ID"]}&code=${authorizationCode}&redirect_uri=app://callback");

    loginLoading.value = true;
    final res = await http.post(uri,
        body: {},
        headers: {'Content-Type': 'application/x-www-form-urlencoded'});
    loginLoading.value = false;

    if (res.statusCode != 200) {
      // Do something with error
    } else {
      // Do something with success
    }
  }

Hope it helps...

@akotorri
Copy link

akotorri commented Jun 20, 2022

Launching a WebView with the Web Authentication process ...

ssoLogin(String method) async {
    String uri =
        "${dotenv.env["COGNITO_POOL_URL"]}oauth2/authorize?redirect_uri=app://callback&response_type=code&client_id=${dotenv.env["COGNITO_CLIENT_ID"]}&identity_provider=$method&scope=phone%20email%20openid%20profile%20aws.cognito.signin.user.admin";
    await launch(uri, forceSafariVC: false);
  }

Where method is facebook, google or signInWithApple. The redirect_uri is the key here, once the web calls the redirect_uri, we retrieve the code as follows.

void _handleIncomingLinks() {
    uriLinkStream.listen((Uri? uri) async {
      if (uri!.queryParameters["code"] != null) {
        ssoWithAuthorizationCode(uri.queryParameters["code"]!);
      }
    }, onError: (Object err) {
      print(err);
    });
  }

and then...

ssoWithAuthorizationCode(String authorizationCode) async {
    final uri = Uri.parse(
        "${dotenv.env["COGNITO_POOL_URL"]}oauth2/token?grant_type=authorization_code&client_id=${dotenv.env["COGNITO_CLIENT_ID"]}&code=${authorizationCode}&redirect_uri=app://callback");

    loginLoading.value = true;
    final res = await http.post(uri,
        body: {},
        headers: {'Content-Type': 'application/x-www-form-urlencoded'});
    loginLoading.value = false;

    if (res.statusCode != 200) {
      // Do something with error
    } else {
      // Do something with success
    }
  }

Hope it helps...

Can you explain where this "uriLinkStream" is coming from that we are putting a listener to? because I can't seem to grasp where that goes or interacts with our code.

And the "ssoLogin(String method)" method requires a string which is named method where do we get that? or what is it to be more precise?

@alextarrago
Copy link

@Zr99
Copy link

Zr99 commented Aug 5, 2023

I have the same issue as you. Do you have any solution for case 19? @akotorri Thanks

@Zr99
Copy link

Zr99 commented Aug 5, 2023

I have tested the View Hosted UI (amazon) in the browser, which is working fine. However, when trying it in the apps, it shows the error code 403 Access Denied Authorisation Access. After some research, it seems like the problem is from Google forcing you to use the System browser rather than 'the browser' in your app. So, the solution that suggests using https://pub.dev/packages/webview_flutter is definitely not gonna work at the moment.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment