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);
}
@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