The current Azure ADB2C Mobile app example here that forcibly opens a browser component outside the app and after Sign-In redirects back to the app.
Is there any way to skip this ugly and clunky Sign-In page altogether and do Sign-In/Sign-up directly from a mobile app component? I want to create my own Sign-In Activity so I only go to the portal to get the token through a REST uri and never have to open a browser outside my app.
You can create a resource owner policy that enables you to gather a user credential in your mobile app and then validate it in your Azure AD B2C tenant.
You can use a client library, such as AppAuth for Android or AppAuth for iOS, to manage the policy invocation for you.
This is an old question, but the question still resonated with me a year later. There is an answer to this:
.WithUseEmbeddedWebView(true)
The full snippet (taken and adapted from an Azure GitHub sample) is:
async void OnLoginButtonClicked(object sender, EventArgs e)
{
AuthenticationResult result;
try
{
//bool useEmbeddedWebView = !App.IsSystemWebViewAvailable;
result = await App.AuthenticationClient
.AcquireTokenInteractive(Constants.Scopes)
.WithPrompt(Prompt.SelectAccount)
.WithParentActivityOrWindow(App.UIParent)
.WithUseEmbeddedWebView(true)
.ExecuteAsync();
await Navigation.PushAsync(new LogoutPage(result));
}
catch (MsalException ex)
{
if (ex.Message != null && ex.Message.Contains("AADB2C90118"))
{
result = await OnForgotPassword();
await Navigation.PushAsync(new LogoutPage(result));
}
else if (ex.ErrorCode != "authentication_canceled")
{
await DisplayAlert("An error has occurred", "Exception message: " + ex.Message, "Dismiss");
}
}
}
Note that this isn't a complete working solution, but it does force the B2C template to load into a WebView rather than opening a browser and revealing your domain name. Put it in the shared code project.
You don't get to use your own login page, but it does at least appear to be part of your app.
Reference: Xamarin Considerations
Hopefully Microsoft will address this failing in future releases.
Related
Following the official guidance, I've implemented the WebAuthenticator in my .NET Maui Android App to handle SSO auth with Facebook.
It's a fairly straightforward implementation, I've added the .Net core backend on a website with the mobile auth endpoint implemented as directed, and that appears to be working.
However when the WebAuthenticator.AuthenticateAsync method is calling the API, it's hanging:
private void OnFacebookClicked(object sending, EventArgs e)
{
try
{
WebAuthenticatorResult authResult = WebAuthenticator.Default.AuthenticateAsync(
new Uri("https://testwebsite.azurewebsites.net/mobileauth/Facebook"),
new Uri("xamarinessentials://")).Result;
string accessToken = authResult?.AccessToken;
}
catch (TaskCanceledException)
{
// User stopped auth
}
}
I don't get any kind of response back - no timeout, no exception, nothing just a straight hang.
Any advice?
I have built a SPA that works in the browser in that on load it provides an auth option, I click google signin and the firebase auth flow continues until I have an auth token etc.
I can then switch the PWA and use as normal. But if I then logout, I cannot log back in again with the App using Google Auth - whether I let the google signin popup run in the App or in Chrome, no confirmation ever gets abck to the App and indeed it seems to crash.
The issue has something to do with the loading of the additional tab for the google signin. According to the onscreen dialog Android asks me whether to open this tab in the PWA or in Chrome. Whichever option I pick, the flow does not complete (and because of the disconnection, I can't see anything useful in devtools).
The only flow that seems to work is to continue the login on chrome and, only when that has completed, switch to the App version. That's fine for me to write on StackOverflow but very complicated for my users.
How can I begin to debug this situation:
- should it be possible to do firebase auth from a PWA; and/or
- is there someway to delay the Android popup to add to home screen to til after the user has logged in on the browser?
Happy to share code, and this is the googlesignin function - it doesn't do anything because I wait for the onAuthState message in my code usually and that has all the information I need.
function signinGoogle() {
var provider = new firebase.auth.GoogleAuthProvider();
firebase.auth().signInWithPopup(provider).then(function(result) {
// This gives you a Google Access Token. You can use it to access the Google API.
var token = result.credential.accessToken;
// The signed-in user info.
var user = result.user;
// ...
}).catch(function(error) {
// Handle Errors here.
var errorCode = error.code;
var errorMessage = error.message;
// The email of the user's account used.
var email = error.email;
// The firebase.auth.AuthCredential type that was used.
var credential = error.credential;
// ...
});
}
Per #jasan 's request, I did find a solution based on #bojeil 's comment
function signinGoogle(cb) {
var provider = new firebase.auth.GoogleAuthProvider();
// firebase.auth().signInWithPopup(provider).then(function(result) {
firebase.auth().signInWithRedirect(provider).then(function(result) {
console.log("Google signin successful")
// This gives you a Google Access Token. You can use it to access the Google API.
// var token = result.credential.accessToken;
// Send user to rest of program
cb(token)
})
.catch(function(error) {
logger(error);
});
}
I'm trying to enable my users to authenticate on Azure AD.
I have registered my app on Azure mobile center, enabled indentity and took note of the Azure auth endpoint.
I also registered my app in the Azure AD app registration as a native app.
I finally went back to my Mobile center to enable Azure AD indentity, set the client ID to be the same as the Azure application ID.
I guess things are not clear enough here for me.
I think that my implementation of the authentication in Xamarin is OK because when I click on my button on my Android project
private async void LoginClick(object sender, EventArgs e)
{
if (App.Authenticator != null)
authenticated = await App.Authenticator.AuthenticateAsync();
}
}
A new window, with the "Authenticate" title, appears. However, I can't get to my endpoint and get the message :
The webpage
https://mobile-{someNumbers}.azurewebsites.net/.auth/login/aad might
be temporarly down or it may have been moved permanently to a new web
address
My authentication method is the most basic one, from a sample :
public async Task<bool> AuthenticateAsync()
{
bool success = false;
try
{
if (user == null)
{
user = await AuthenticationManager.DefaultManager.CurrentClient.LoginAsync(this, MobileServiceAuthenticationProvider.WindowsAzureActiveDirectory);
if (user != null)
{
System.Diagnostics.Debug.WriteLine("Authenticated !");
}
}
success = true;
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine(ex.Message);
}
return success;
}
}
Has anyone met this issue before ?
Any pointers on how to be able to log in to the AD services ?
Thank you in advance!
According to your description, I assumed that you could leverage the server-flow authentication to test that you have all the settings correct. Browser at https://yoursite.azurewebsites.net/.auth/login/aad and find that whether you could get the successful authentication page. For more detailed tutorials about AAD authentication for Azure Mobile Apps, you could refer to Adrian Hall's blog here. Additionally, for Client-managed and Server-managed authentication for Mobile Apps, you could follow this official tutorial.
I am trying to set up a proper facebook login in my react native app. For now I have it working in a pure webview with oauth login to my server but I want to use the native facebook login to be able to take advantage of the facebook app.
I am using the following libraries:
Server side
https://github.com/FriendsOfSymfony/FOSUserBundle
https://github.com/hwi/HWIOAuthBundle
https://github.com/FriendsOfSymfony/FOSOAuthServerBundle
App side
https://github.com/magus/react-native-facebook-login
So my facebook login is perfectly functional on my website as well as on my app in a webview for OAuth by calling /oauth/v2/auth in a webview and handling the token.
But it is kinda messy because in the webview you have to type your full email + password combo.
So right now I'm just getting an authorization error when calling /login/facebook-check in a webview on the Login success event (by the native plugin), I could use some help to finish this.
Finally made it work. The hack was to use all the existing services to work together.
I made a custom controller. Some security checks are needed but still this works:
/**
* #Route("/api/facebook-connect/{accessToken}", name="api_facebook_connect", defaults={"_format" = "json"})
* #Rest\View()
*/
public function facebookLoginAction($accessToken, Request $request)
{
$token = new OAuthToken($accessToken);
$token->setResourceOwnerName('facebook');
$oauthUserProvider = $this->get('app.oauth.provider.user_provider');
$ressourceOwnerMap = $this->get('hwi_oauth.resource_ownermap.main');
$userChecker = new UserChecker();
$oauthProvider = new OAuthProvider($oauthUserProvider, $ressourceOwnerMap, $userChecker);
$token = $oauthProvider->authenticate($token);
$this->get('security.token_storage')->setToken($token);
$client = $this->get('doctrine.orm.entity_manager')->getRepository('AppBundle:Client')->findOneBy([], ['id' => 'DESC']);
$oauth2server = $this->get('fos_oauth_server.server');
$accessToken = $oauth2server->createAccessToken($client, $this->getUser(), 'user', 3600);
return $accessToken;
}
Will update this as I clean this up.
I'm not sure about how to properly handle the server-side part, however here are a few details about how we integrated Facebook login in one of our app:
We first started by using https://github.com/magus/react-native-facebook-login but later switched to https://github.com/facebook/react-native-fbsdk, which is maintained by Facebook and allow to access to other Facebook services (in particular, we used the Share API)
In both case (react-native-fbsdk or not), the flow was like this:
We have a Connect with Facebook button (a normal button, nothing fancy - we're not using the one provided by the modules).
When clicked, we call the Login method with the appropriate permissions. This should work out of the box, meaning that you'll have either a webview displayed (if you don't have the Facebook app) or the native Facebook app shown.
If the user declines the login to the app, nothing will happen.
If the user accepts, the app will receive the Access Token that can be used to issue calls to the Facebook API on the behalf of the user. This looks like this using react-native-fbsdk:
// This can be put in a Facebook login button component or a service,
// and should be called when the user wants to connect with Facebook
LoginManager.logInWithReadPermissions(permissions).then((result) => {
if (result.isCancelled) {
this.props.onCancel();
return;
}
AccessToken.getCurrentAccessToken().then((data) => {
this.props.onLogin(data);
});
}, (error) => {
console.warn('Facebook Error', error);
});
We then send the access token to our server which is able to fetch the profile of the user via the Facebook Graph API, creating a user account on the server if needed (i.e: if it's the first time the user log on).
// Called once we got the access token from the data in the previous
// step (this.props.onLogin(data)).
loginWithFacebook(facebookAccessToken) {
return fetch(`${apiHost}/api/login/facebook`, {
method: 'GET',
headers: {
// We pass the access token using the Authorization header:
Authorization: `Bearer ${facebookAccessToken}`,
},
}).then(() => {
// Whatever, for example get the user info returned by the server
// and store them.
});
}
On the server, we get the Access Token from the headers and use it to get the user profile (populating the account of the user for our app, for example with his avatar and name) and associate the user account with the facebook id of the user.
If the user have the Facebook app and already accepted the app, nothing will be asked to him the next time he tries to log in. You just click on the login button and get logged to the app :)
If the user don't have the Facebook app, the Facebook SDK always display a webview with the login page.
Hope this can help!
I am building an android app which pays someone. I explored Stripe Connect and it has an API and flow for website which requires displaying a stripe connect button and also needs a re-direct uri.
However, I can not find anything on for Android which allows to show a connect button and prompt user to create or connect a stripe account natively on Android device. Should I use a webview to do this or is there some more elegant way to do this?
As far as I know, there're no native SDK for mobile stripe connect. I did the webview route for android. Was trivial, but I agree that I wished there're a more elegant solution to this.
For those who are wondering on how to do this (since I can't find any doc out there), here you go:
Create a button that will open a new intent with a web view.
The webview should load the oauth/authorize endpoint ("https://connect.stripe.com/oauth/authorize?response_type=code&client_id=[YOUR_API_KEY]&scope=read_write"). Do not forget to enable javascript on your webview.
Once the form in webview is filled, Stripe will redirect to the redirect_url you provided with the authorization code if the authorization is successful. Have your web service parse that authorization code.
Have your service make a post to stripe oauth/token with providing grant_type, client_id, code, and client_secret.
Stripe will then respond back with the token (auth credentials) that you needed. Store that for later use & you're pretty much done.
I know this is quite an old one but, After investing my 2 days and trying, searching a lot of techniques to create stripe account in android platform I found Stripe API which solves my problem...
Firstly, here is the jar file you have to include in your project.
Then you have to initialize key provided you at the dashboard
Stripe.apiKey = "sk_test_xxxxxxxxxxxxxxxxxxxxxxxx";
RequestOptions requestOptions = RequestOptions.builder()
.setApiKey("sk_test_xxxxxxxxxxxxxxxxxxxxxxxx").build();
Map<String, Object> accountParams = new HashMap<String, Object>();
accountParams.put("managed", false);
accountParams.put("country", "US");
accountParams.put("email", "some#email.com");
To create an account use create() method for Account class with there parameter create link
try {
Account create = Account.create(accountParams, null);
} catch (AuthenticationException e) {
e.printStackTrace();
}
Then to retrieve account detail pass account id to retrieve() method
try {
Account detail = Account.retrieve("acct_xxxxxxxxxxxxxx", null);
} catch (AuthenticationException e) {
e.printStackTrace();
}
You can find more at Stripe Android API, and yes please do correct me if I am wrong..
Exception you need to catch AuthenticationException, InvalidRequestException, APIConnectionException, CardException, APIException