flutter: HttpException: Failed Forbidden from the twitter plugin - android

I'm trying to implement twitter login in my app but it doesn't work, returning an errorMessage in the AppResult object. Does anyone know a solution?
The packages I use are
twitter_login: ^4.2.3
firebase:
firebase_core: ^1.11.0
firebase_auth: ^3.3.5
Twitter config (User authentication settings page):
OAuth 1.0a enabled (is it the proper one for the plugin?)
Request email from users: disabled
App permissions: Read
Callback URI: https://project-name.firebaseapp.com/__/auth/handler
webiste url: https://www.google.com/
besides that everything is empty
Firebase config:
twitter auth enabled
api key set (checked it like 10 times)
api secret set (same thing)
Android manifest:
inside the activity tag:
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<!-- Accepts URIs that begin with "example://gizmos” -->
<!-- Registered Callback URLs in TwitterApp -->
<data android:scheme="https" android:host="app-name.firebaseapp.com" />
<!-- host is option -->
</intent-filter>
after the activity tag:
<meta-data android:name="flutterEmbedding" android:value="2" />
The code itself:
final twitterLogin = TwitterLogin(
apiKey: '123 it's the same one',
apiSecretKey: 'proper one',
redirectURI: 'https://app-name.firebaseapp.com/__/auth/handler');
final authResult = await twitterLogin.login();
print(authResult.errorMessage); // prints out HttpException: Failed Forbidden
The code opens the link with the authentication, but after clicking on "authorize app", it returns to the app with the errorMessage "HttpException: Failed Forbidden"
Also, the authToken and the authTokenSecret are both null.
If you need any additional information, please let me know!

Your getting Forbidden http exception. So, in the official documentation it says -
The request is understood, but it has been refused or access is not allowed. An accompanying error message will explain why.
And the solution is given as -
Check that your developer account includes access to the endpoint you’re trying to use. You may also need to get your App allowlisted (e.g. Engagement API or Ads API) or sign up for access.
You can check - Twitter API Documentation
Hope it helps.

So, after a little bit of digging I found the answer to my question. In order to make it work I did the following:
changed the android scheme to appname://
removed the android host
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE"/>
<!-- Accepts URIs that begin with "example://gizmos” -->
<!-- Registered Callback URLs in TwitterApp -->
<data android:scheme="appname" />
<!-- host is option -->
</intent-filter>
changed the redirect url inside the twitter config to appname://
got elevated access for the twitter portal
used the loginV2 function along with OAuth2 instead of OAuth1
Future<UserCredential> _signInWithTwitter() async {
// Create a TwitterLogin instance
final twitterLogin = TwitterLogin(
apiKey: '123',
apiSecretKey: '1234',
redirectURI: 'appname://');
// Trigger the sign-in flow
final authResult = await twitterLogin.loginV2();
print(authResult.toMap());
// Create a credential from the access token
final twitterAuthCredential = TwitterAuthProvider.credential(
accessToken: authResult.authToken!,
secret: authResult.authTokenSecret!,
);
// Once signed in, return the UserCredential
return await FirebaseAuth.instance
.signInWithCredential(twitterAuthCredential);
}
Didn't use the callback provided by firebase at all (this is mentioned in the README too, but I'm too stupid to check)

Related

Xamarin Forms Android - Authentication Failure on Deployment using MSAL Library

Development Information - Xamarin Forms Mobile application, utilizes MSAL library version 4.35.0 to authenticate against Azure AD and uses Brokered authentication flow utilizing the Microsoft Authenticator. This is coded in Visual Studio 2019 using C# and .Net 5.
Problem - Everything works in the Android emulator, but once deployed to an actual device, using Company Portal (Intune), the authentication piece fails with message:
Authentication Error [Android broker] The broker redirect URI is incorrect, it should be msauth://com.xxxxxx.xxxxxxx/xxxxxxxxxxxxxx Please visit https://aka.ms/Brokered-Authentication-for-Android for more details
I compared the redirect uri in the Azure portal to the one being displayed in the error message and they don't match, I don't know where it's getting this redirect uri value from?? Everything in the code base uses the callback uri specified in the Azure portal
I've worked through multiple MSDN documents, download example projects from GitHub, modified the Android Manifest file, etc. None of that seems to fix this issue. I am at my wits end with this. Here is an example of the Authentication code:
public static IPublicClientApplication PCA;
//OAuthSettings is a class containing my values to pass to the methods of the
//PublicClientApplicationBuilder
var builder = PublicClientApplicationBuilder
.Create(OAuthSettings.ApplicationId)
.WithTenantId(OAuthSettings.TenantId)
.WithBroker()
.WithRedirectUri(OAuthSettings.RedirectUri);
PCA = builder.Build();
try
{
var accounts = await PCA.GetAccountsAsync();
var silentAuthResult = await PCA
.AcquireTokenSilent(new string[] { "api://xxxxxxxxxxxxxx/.default" }, accounts.FirstOrDefault())
.ExecuteAsync();
AccessToken = new JwtSecurityToken(silentAuthResult.AccessToken);
//more code removed for brevity
}
catch (MsalUiRequiredException msalEx)
{
var windowLocatorService = DependencyService.Get<IParentWindowLocatorService>();
// Prompt the user to sign-in
var interactiveRequest = PCA.AcquireTokenInteractive(new string[] { "api://xxxxxxxxxxxxxxxxxxx/.default" });
//Used for Android and iOS
AuthUIParent = windowLocatorService?.GetCurrentParentWindow();
if (AuthUIParent != null)
{
interactiveRequest = interactiveRequest
.WithParentActivityOrWindow(AuthUIParent);
}
//
var interactiveAuthResult = await interactiveRequest.ExecuteAsync();
AccessToken = new JwtSecurityToken(interactiveAuthResult.AccessToken);
}
Android Manifest
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionName="1.0" package="com.gpdgroup.GPDMobileAppTest" android:installLocation="auto" android:versionCode="7">
<uses-sdk android:minSdkVersion="21" android:targetSdkVersion="30" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<application android:label="mycompany.Android" android:theme="#style/MainTheme" android:usesCleartextTraffic="true" android:icon="#mipmap/icon" android:roundIcon="#mipmap/icon">
<activity android:name="microsoft.identity.client.BrowserTabActivity">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="msal{clientID}" android:host="auth" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="msauth" android:host="com.mycompany.myapp" android:path="/{base64 hash}" />
</intent-filter>
</activity>
</application>
<!--Necessary to fix issue on authentication for level 30-->
<queries>
<package android:name="com.azure.authenticator" />
<package android:name="com.mycompany.myapp" />
<package android:name="com.microsoft.windowsintune.companyportal" />
<!-- Required for API Level 30 to make sure the app detect browsers
(that don't support custom tabs) -->
<intent>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="https" />
</intent>
<!-- Required for API Level 30 to make sure the app can detect browsers that support custom tabs -->
<!-- https://developers.google.com/web/updates/2020/07/custom-tabs-android-11#detecting_browsers_that_support_custom_tabs -->
<intent>
<action android:name="android.support.customtabs.action.CustomTabsService" />
</intent>
</queries>
</manifest>
Screenshot of Azure Portal:
I also added an MSAL Authentication JSON file to the Resources folder of the Android project in a sub folder called raw called msal_default_config.json:
{
"client_id": "xxxxxxxxxxxxxxxxxxxxx",
"redirect_uri": "msauth://com.mycompany.myapp/{base64 url encoded signature hash}",
"broker_redirect_uri_registered": true,
"account_mode" : "SINGLE",
"authorities": [
{ "type": "AAD", "audience": { "type": "AzureADandPersonalMicrosoftAccount",
"tenant_id": "xxxxxxxxxxxxxxxxxx" }
} ]
}
And I also have this class for the Android project which inherits BrowserTabActivity class, called MsalActivity:
[Activity]
[IntentFilter(new[] { Intent.ActionView },
Categories = new[] { Intent.CategoryBrowsable, Intent.CategoryDefault },
DataHost = "auth",
DataScheme = "msal{clientID}")]
public class MsalActivity : BrowserTabActivity
{
}
The way Google has architected the mechanism through which one app can invoke another app mandates that the redirect URI has to include a signature of the application pkg.
The problem is that every Android SDK deployment has its own signature. So when you develop the app, you have one signature. When another developer tries to build and deploy, it's another signature. And when you create the official app that you submit, well there's another signature as well. They all use different Android SDKs.
SO you need to register 1 redirect URI for each app developer AND 1 redirect URI for the packaged bits.
You should expect that future versions of your application will have the same signature, so this process is done only once.
So after multiple changes and trying different things, we got it working, but we had to do the following:
I had my co-worker who manages the Play Store, create a new Application for release. (Not sure if this was necessary)
I changed the package name of the Android application to be all lower case. (Not sure if this was necessary)
Used the following to get the production signing key hash so that we could add it to the Azure portal. Production Signing Hash
How we got the production signature hash:
A. My co-worker who manages the Play Store, gave me the Hexadecmial SHA-1 value of the Application Signing from Google Play for the newly created application
B. Used the answer by Sujeet Kumar to get the base64 hash by feeding the Hexadecimal value into Chrome's console window with the following:
btoa('{your hexadecimal value goes here without the curly brackets}'.split(':')
.map(hc => String.fromCharCode(parseInt(hc, 16))).join(''))
C. Took this base64 hash and put it under the application Android callback uri section of the Azure portal
Since no one gave me this last step of how to get the production signature hash, I thought it may be helpful to put the steps I used to get it here.

How does Google Sign in for Android work without a redirect uri?

The Google Sign in library on Android works without specifying any redirect uri. Why is this the case? To which endpoint does Google send the access code to after the user logs in? And how does it redirect the user back to the app?
Thanks.
Now I see, the redirect uri is in fact the app itself, using a uri that points to a page on the app, not to any website. The redirect uri can be set up in the Android app by using the information here: https://developer.android.com/training/app-links/deep-linking. I learned a lot from this youtube video: https://www.youtube.com/watch?v=j3OTZ62AkNU
Once it redirects the user back to the app, the google sign in library handles getting the token and user info.
com.googleusercontent.apps.123:redirect_uri_path
com.example.app is the reverse DNS notation of a domain under your control. The custom scheme must contain a period to be valid.
com.googleusercontent.apps.123 is the reverse DNS notation of the client ID.
redirect_uri_path is an optional path component, such as /oauth2redirect. Note that the path should begin with a single slash, which is different from regular HTTP URLs.
^ Copied from documentation. 123 is your client id. And com.googleusercontent.apps is fixed, not variable. Setting this as the redirect uri in your app will make sure that google directs user back to your app, where the library will handle getting the access token and user profile, etc. You need to have an intent filter in your manifest.xml (or the following in Xamarin) to receive the uri.
[IntentFilter(
new[] { Intent.ActionView },
Categories = new[] { Intent.CategoryDefault, Intent.CategoryBrowsable },
DataSchemes = new[] { "com.googleusercontent.apps.123" },
DataPath = "/oauth2redirect")]
Its equivalent in the Manifest.xml:
<activity android:label="ActivityCustomUrlSchemeInterceptor" android:launchMode="singleTop" android:noHistory="true" android:name="crc640d96480bfe206cdf.ActivityCustomUrlSchemeInterceptor">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:path="/oauth2redirect" />
<data android:scheme="com.googleusercontent.apps.123" />
</intent-filter>
</activity>

Flutter Spotify Api Authentication

I need to authenticate user in my Flutter app which uses Spotify api.
I use flutter_web_auth to open WebView and let user login there.
I can't make it to return to app.
In Spotify Dashboard i have callback Uri set to: https://spotifydata.com/callback
final callbackUrl = "https://spotifydata.com/callback";
void _authenticateSpotfy() async {
final url = Uri.https('accounts.spotify.com', '/authorize', {
'response_type': 'code',
'client_id': clientID,
'redirect_uri': 'https://spotifydata.com/callback:/',
'scope': 'user-read-private user-read-email',
});
final result = await FlutterWebAuth.authenticate(
url: url.toString(), callbackUrlScheme: callbackUrl);
}
AndroidManifest.xml
<activity android:name="com.linusu.flutter_web_auth.CallbackActivity" >
<intent-filter android:label="flutter_web_auth">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="https://spotifydata.com/callback" />
</intent-filter>
</activity>
I have tried other answers on Stack but they don't seem to work.
As mentioned in Spotify's API docs, authentication redirects the user to the defined redirect_uri on successful request. Trying to log-in on https://spotifydata.com/, it has redirect_uri set as redirect_uri=https%3A%2F%2Fspotifydata.com%2Fsongdata. Make sure that the defined redirect_uri matches the callback scheme configured in the Manifest file since this enables the app to handle the redirect URL via the intent-filter.

Unable to authenticate with Microsoft using Firebase

I'm trying to implement authentication with Microsoft using Firebase in my app. I followed the steps mentioned in the tutorial https://firebase.google.com/docs/auth/android/microsoft-oauth.
Following are the code snippets from my application -
MSAuthManager.java
public void loginOutlook(Context context) {
FirebaseAuth firebaseAuth = FirebaseAuth.getInstance();
Task<AuthResult> pendingResultTask = firebaseAuth.getPendingAuthResult();
if (pendingResultTask == null) {
OAuthProvider.Builder provider = OAuthProvider.newBuilder("microsoft.com");
provider.setScopes(asList(SCOPES));
firebaseAuth.startActivityForSignInWithProvider((Activity) context, provider.build())
.addOnSuccessListener(this)
.addOnFailureListener(this)
.addOnCanceledListener(this);
}
}
AndroidManifest.xml
<activity android:name="com.microsoft.identity.client.BrowserTabActivity">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="https://**********.firebaseapp.com/__/auth/handler"
android:host="auth" />
</intent-filter>
</activity>
Note - I have already authenticated the user with Google sign-in using Firebase on the Login Screen.
However, when I start the authentication process, a custom tab launches takes me to the Microsoft login page and then automatically closes and redirects me back to my app with the following error -
FirebaseAuthWebException: The web operation was canceled by the user.
Could anyone please tell me what am I missing here?
I had the same problems, and for me it's because the entered password is wrong so -> The web operation was canceled by the user.
You have to managed saved password or clear cache and data for chrome or samsung internet browser.

android twitter outh tutorial callback problem

Trying the following tutorial
http://www.androidsdkforum.com/android-sdk-development/3-oauth-twitter.html
i am having trouble understanding callback URL
my twitter app name is "faisal-android" and my call back url i defined in code is
myapp://wozzon-android
and having entry in xml file as
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="myapp" android:host="faisal-android" />
</intent-filter>
m i way to defining callback url is correct ??
when i run the code it gives me error "Authorization failed (server replied with a 401). This can happen if the consumer key was not correct or the signatures did not match"
my twitter app account settings as following
alt text http://www.freeimagehosting.net/uploads/a0c2689c73.png
I think you need to check browser and not client if you use a callback url
I read something about this :
http://blog.sogeti.com/mobile/2010/03/twitter-oauth-for-android.html
(dead link)
Android – OAuth updates to Twitter
http://dev.bostone.us/2009/07/16/android-oauth-twitter-updates/#awp::2009/07/16/android-oauth-twitter-updates/
Check your callback UL in twitter . Enter any dummy URL not kept empty .
You can write google.com, it work in my case.

Categories

Resources