Error launching browser in Google.Apis.Auth.OAuth2.LocalServerCodeReceiver on Android - android

I'm trying to authenticate an end-user in an android app written in C# (Xamarin.Android).
I decided to try and use NuGet package Google.Apis.Oauth.v2 which seems to expose an easy to use Oauth client.
LocalServerCodeReceiver.ReceiveCodeAsync throws the following:
I get System.NotSupportedException:"Failed to launch browser with https://XXX.auth.XXX.amazoncognito.com/login?response_type=token&client_id=XXX&redirect_uri=https%3A%2F%2Fwww.google.com&scope=profile%20openid%20email for authorization. See inner exception for details."
and it has an inner exception of System.ComponentModel.Win32Exception:"Cannot find the specified file"
Code:
var clientSecret = new Google.Apis.Auth.OAuth2.ClientSecrets();
clientSecret.ClientId = ...
clientSecret.ClientSecret = ...
var initializer = new Google.Apis.Auth.OAuth2.Flows.AuthorizationCodeFlow.Initializer(
"https://XXX.auth.XXX.amazoncognito.com/login",
"https://XXX.auth.XXX.amazoncognito.com/login");
initializer.Scopes = new List<string> {"profile", "openid", "email"};
initializer.ClientSecrets = clientSecret;
var flow = new Google.Apis.Auth.OAuth2.Flows.AuthorizationCodeFlow(initializer);
var authCodeRequestURL = flow.CreateAuthorizationCodeRequest("https://www.google.com");
authCodeRequestURL.ResponseType = "token";
var uri = authCodeRequestURL.Build();
var cancellationTokenSource = new System.Threading.CancellationTokenSource();
var codeReceiver = new Google.Apis.Auth.OAuth2.LocalServerCodeReceiver();
var task = codeReceiver.ReceiveCodeAsync(authCodeRequestURL, cancellationTokenSource.Token);
Do I need to ask for a specific permission in the application manifest?
Instead of redirecting to www.google.com, I've heard you can redirect to an app, I'm not really sure how to do that, is it http://my_app_package_name or http://my_app_title, something else?
Is it possible not to rely on that library for launching the browser and instead get the RequestUri and start an Activity, if so how will the app become aware the end-user completed the SignIn process and how will the app retrieve the token?

Sorry, but Google.Apis.Oauth.v2 does not support Xamarin, and there's no simple way to get it working.
Unfortunately no Google.Apis.* packages currently support Xamarin.
You might find the Xamarin.Auth package does what you want?

I've figured out how to redirect to an app after authentication in the browser completes.
It's called a "Deep Link" and it's documented at enter link description here, essentially you need to declare an IntentFilter on your Activity, which registers with the Android OS that if someone clicks or an page redirects to a specific URI, your app gets called. The token that's appended to the URI can then be read inside your app.

Related

How to initialize Sign Client of WalletConnect (Android SDK)

I have following problem. I just can't figure out how to initialize WalletConnect and connect to Metamask on Android. I always get following exception.
java.lang.NoSuchMethodError: No interface method getInitializationErrorsFlow()Lkotlinx/coroutines/flow/Flow; in class Lcom/walletconnect/android/internal/common/model/JsonRpcInteractorInterface;
My code looks as follows:
val projectId = "15f2b4ae8bb12dsd3d267ce6441d5a9d" // I got the Project ID from https://cloud.walletconnect.com/
val relayUrl = "relay.walletconnect.com"
val serverUrl = "wss://$relayUrl?projectId=$projectId"
val connectionType = ConnectionType.AUTOMATIC
val appMetaData = Core.Model.AppMetaData( // <-- What data should be entered here?
name = "Metamask",
description = "Description",
url = "Wallet Url", // How can I get the wallet url?
icons = listOf(""),
redirect = "kotlin-wallet-wc:/request"
)
CoreClient.initialize(relayServerUrl = serverUrl, connectionType = connectionType, application = application, metaData = appMetaData)
val init = Sign.Params.Init(CoreClient)
SignClient.initialize(init, onError = { error ->
})
Are you calling all initialize methods inside the Application onCreate() method? We have a demo wallet to showcase how it should be done here
enter code here
wc:a593bc04-32b5-4e25-aaec-9e2c247e868a#1?bridge=https%3A%2F%2Fv.bridge.walletconnect.org&key=be7212e692f047b39425b0fe88d805582ac29aa76ccb893d5c0cdef8845dc3c3
All the answers are from this tutorial: Connect a iOS or Android DApp to Web3 Wallet. I strongly recommend reading it.
1. "What data should be entered here?":
It's the data about your DApp, it allows the end user to recognize and decide to grant you rights when his wallet asks for it.
Here is a simple example:
private val metaData = Session.PeerMeta(
name = "nfscene",
url = "nfscene.com",
description = "nfscene WalletConnect demo"
)
2. "How can I get the wallet URL?"
You need to understand that the end-user can choose his wallet. So you can't force the wallet to be used. Knowing what Wallet the user use is not your concern as the transactions are sent through the Wallet Connect bridge. If you only want to allow the use of MetaMask you should directly use the MetaMask API.
you using 2.0.0?
it was fixed in 2.1.0.

ionic2 get data from system browser

I'm working on an Ionic 2 app which requires logging in using external link. For security reason I would prefer to open the link in system browser. After I open the link and login with username & password, a token will be returned in the body of the html. Is there a way to pass that token to my app? Or are there any other solutions to tackle this problem? Thank you.
This is extremely conceptual, but you could use the cordova plugin inappbrowser to open a browser inside the app, listen to the exit event to wait for the user to close the in-app browser, and there inject a script to retrieve the token from the html, something like:
inAppBrowserRef = undefined;
showLogin(url) {
var target = "_blank";
var options = "location=yes,hidden=yes";
this.inAppBrowserRef = cordova.InAppBrowser.open(url, target, options);
with (this.inAppBrowserRef) {
addEventListener('exit', this.exitCallBack);
}
}
exitCallBack(params) {
captureToken = "return token = [[jquery to retrieve the token]]";
this.inAppBrowserRef.executeScript({ code: captureToken}, this.executeScriptCallBack);
this.inAppBrowserRef.close();
this.inAppBrowserRef = undefined;
}
executeScriptCallBack(token) {
this.token=token;
}

How to set android backend minSdk

im working on an android app with some server-side business logic. Im using android studio and im creating that kind of app for a first time.
I am trying to use server-side application to login to a different system and return me a cookie, so my android application can tell, whether the set credentials are correct.
Here's my endpoint provided method.
/** Returns user with cookie set either to null or actual cookie from AIS */
#ApiMethod(name = "login")
public User login(#Named("loginName") String name, #Named("password") String password) {
AISCommunicator aisCommunicator = new AISCommunicator();
String cookieVal = aisCommunicator.login(password,name);
User user = new User();
user.setCookie(cookieVal);
//user.setCookie("asdasdasd");
return user;
}
AISCommunicator is a serverside bean. At the moment it's part of a code
CookieManager manager = new CookieManager();
manager.setCookiePolicy(CookiePolicy.ACCEPT_ALL);
CookieHandler.setDefault(manager);
is marked as incorrect by Android studio, which tells me, that to use it, i need to declare minSdk level 9, while currently i have 1. How can i do that? I have set minSdk in my client's app, but it seems like it does not influence the serverside bean.
Anyway, the code is still runnable for some reason and the endpoint Bean returns 404 not found error at the moment.
Ignore Android Studio's error. This is one of its known and unfixed bugs.

How can I access the values passed into my app via a custom url scheme from within my C# code?

I'm working on a Xamarin Forms application. It has an Entry field for the visit code on the initial page. I need to extend its functionality so that the application will open when a custom url scheme myscheme://visitcode is encountered, and the Entry will have its Text value prepopulated with the value of visitcode.
I've had success with getting the application to launch.
I added my scheme to the info.plist file in my iOS project, and it properly launches the app when I click on my custom url scheme in Safari on an iPhone.
I added the following line above my MainActivity in my Droid project:
[IntentFilter(new[] { Intent.ActionView }, Categories = new[] { Intent.CategoryDefault, Intent.CategoryBrowsable }, DataScheme = "myscheme")]
It properly launches the app when I click on my custom url scheme in Chrome on an Android phone.
The only remaining obstacle is to retrieve the value and populate the Entry field with it.
Can someone help me?
Note: I haven't tested this yet, so make sure your app lifecycle and the place where you handle the events are matching the Xamarin.Forms app lifecycle. That is, make sure Xamarin.Forms.Application.Current is not null. If it is, reshuffle your code to work around that.
For iOS, you have to override OpenUrl in your AppDelegate.cs:
public override bool OpenUrl (UIApplication application, NSUrl url, string sourceApplication, NSObject annotation);
and in Android, you handle that in your MainActivity.cs, in your OnCreate or any other method used as entry point:
var intent = Intent;
var uri = intent.Data;
That should allow you to retrieve the parameters of the url.
You then can retrieve the current Xamarin.Forms Application object, by doing:
var myapp = Xamarin.Forms.Application.Current as MyApplication;
Now, it's up to you to retrieve the right entry, or it's view model, or a service or whatever to connect the dots.
There is a component within the Xamarin store that handles this for you:
http://components.xamarin.com/view/rivets
This will remove the lengthy code requirements in building native implementations.

Java based Google App Engine, Android and authentication oauth2

Authentication and app engine, there is a lot to be read about it, but a lot seems to be outdated!
Even the google pages https://developers.google.com/appengine/docs/java/endpoints/consume_android#making-authenticated-calls
Here, they talk about 'GoogleAccountCredential.usingAudience', but nowadays, you should use GoogleAuthUtil (as far as I know, please correct me if I'm wrong).
I am trying to set up an app engine as a backend to my Android app (and in future, my iOS app).
I am using Android Studio, used the 'new module' and chose app engine with cloud messaging there.
I created a simple endpoint, and have a function there, here is some code:
public class ReviewEndpoint {
// Make sure to add this endpoint to your web.xml file if this is a web application.
private static final Logger LOG = Logger.getLogger(ReviewEndpoint.class.getName());
/**
* This method gets the <code>Review</code> object associated with the specified <code>id</code>.
* #param id The id of the object to be returned.
* #return The <code>Review</code> associated with <code>id</code>.
*/
#ApiMethod(name = "getReview")
public Review getReview(#Named("id") Long id) {
// Implement this function
Review r = new Review();
r.setData("test!");
As you can see, this is nicely generated by Android Studio. I implemented some stuf like creating the 'review' object and return it at the end.
On the Android side, I can do this:
ReviewEndpoint.Builder b = new ReviewEndpoint.Builder(AndroidHttp.newCompatibleTransport(), new AndroidJsonFactory(), null);
ReviewEndpoint ep = b.build();
Review review = ep.getReview(1L).execute();
data = review.getData();
and yes, I get 'test!' :)
Now, I want to have this authenticated. I want to know which user wrote what, so I thought I am going to use GMail account and Facebook later.
Here I'm stuck. I am able to get a token from the user on Android:
token = GoogleAuthUtil.getToken(MainScreenActivity.this, mAccount.name, "oauth2:https://www.googleapis.com/auth/plus.me https://www.googleapis.com/auth/userinfo.profile");
then you are able to add this token as credential to the request:
Credential cr = new Credential(BearerToken.authorizationHeaderAccessMethod()).setAccessToken(token);
ReviewEndpoint.Builder b = new ReviewEndpoint.Builder(AndroidHttp.newCompatibleTransport(), new AndroidJsonFactory(), cr);
Then in the app engine I tried to get the user info, but how?
Will it be supplied as 'bearer'? How do I get this bearer token? Should I then do API request to get the data on the server?
this does not work:
OAuthService service = OAuthServiceFactory.getOAuthService();
try {
User user = service.getCurrentUser();
can anyone give me a heads up?
So finally, today, I found out how to do it! I had questions on Stackoverflow on this before and never had an answer, but these to sites gave me the answer:
https://developers.google.com/appengine/docs/java/endpoints/auth
https://developers.google.com/appengine/docs/java/endpoints/consume_android
The first shows what needs to be done on the app engine side. The second page will tell you how to get the credentials. I was quite close. I am not sure if the adjusting of the build.gradle file mentioned in the second link is necessary. What I added to the App Engine:
#Api(name = "reviewEndpoint", version = "v1", ...<<some more stuff here >>
scopes = {Constants.EMAIL_SCOPE},
clientIds = {Constants.WEB_CLIENT_ID, Constants.ANDROID_CLIENT_ID},
audiences = {Constants.ANDROID_AUDIENCE})
and then get the credentials:
// Initialize the scope using the client ID you got from the Console.
final String scope = "server:client_id:" + Constants.WEB_CLIENT_ID;
credential = GoogleAccountCredential.usingAudience(activity,scope);
You have to add the e-mail address of the user:
credential.setSelectedAccountName("some-mail-address#gmail.com");
you can get the e-mail address using the account picker (also example shown when you follow the link)
and next. you do a call to the endpoint, using the credential, I think Play Services will validate the user, because if I use an e-mail that is not logged in on the device, it will not work. The following code will throw an GoogleAuthIOException :
ReviewEndpoint.Builder b = new ReviewEndpoint.Builder(
AndroidHttp.newCompatibleTransport(),
new AndroidJsonFactory(), id_token);
ReviewEndpoint ep = b.build();
Review review;
review = ep.getReview(1L).execute();
for testing, I've put the e-mail address I get at the server side as a string in the review object, and there it gave me the e-mail address instead of the user object being null. Ow! I forgot to tell you, you need a user argument on the app engine side. Even though you do not see the 'user' argument in the 'getReview' call above, it will be added by App Engine.
So this is how my getReview looks now:
#ApiMethod(name = "getReview")
public Review getReview(#Named("id") Long id, User user) {
// Implement this function
Review r = new Review();
r.setData("user == " + (user == null ? "NULL " : user.toString()));
Hope this will help someone

Categories

Resources