I am trying to implement Microsoft SSO authentication in ionic 5.
Undefine occurs in the console when the code below is executed. Which part is the problem?
login(){
let authContext: AuthenticationContext = this.msAdal.createAuthenticationContext('https://login.windows.net/common');
authContext.acquireTokenAsync('https://graph.windows.net', 'clientID', 'http://localhost:8200')
.then((authResponse: AuthenticationResult) => {
console.log('Token is' , authResponse.accessToken);
console.log('Token will expire on', authResponse.expiresOn);
})
.catch((e: any) => console.log('Authentication failed', e));
}
error =>
https://ionicframework.com/docs/v3/native/ms-adal/
const browser = this_.iab.create("https://login.microsoftonline.com/" + tenant_id +
"/oauth2/authorize?response_type=id_token&client_id=" + client_id
+"&state=SomeState&nonce=SomeNonce"
, '_blank', 'clearsessioncache=yes,clearcache=yes,toolbar=no,location=no,toolbarposition=top,hidenavigationbuttons=yes,toolbarcolor=#0072bb')
browser.on("loadstart").subscribe(event => {
IAB is inappbrowser. Msal we had also tried to use when we needed this type of authentication for azure AD b2c. Similarly you have to do for your case.
There is enterprise level plugin available which cost around 8 lakhs INR.
So this is the work around. Tenant id and client id you will get when you register your app under applications in azure account.
So once the login is successful that load listener will listen to pages which IAB is visiting. And if found occurrence of #token_id(after sucesfull login).
Automatically the iab will close and ionic app page will resume or you can put some new route entry in that event listener.
May be for your case the base url might change. So try first visiting chrome with the url which opens your case login. And accordingly change.
MAKE IT WORK USING IAB AND NOT MSAL
Related
I am developing an SPA with Laravel 9, Vuejs 3 and Sanctum. I am newbie to vue and to Sanctum and I use the sanctum API authentication instead of the token authentication.
At this stage I am in dev and run the embedded laravel server for laravel app and vite server for SPA.
Everything is going smoothly when I sign in and out using the Firefox browser. But when I use Google Chrome or other browser based upon chrome (Brave, Vivaldi, chromium) I cannot sign in nor register. I get a CSRF token mismatch response.
Here are my login an register methods from vuex 's store
actions: {
async register({ commit }, form) {
console.log("in register of index");
await axiosClient.get("/sanctum/csrf-cookie");
return axiosClient.post("/api/register", form).then(({ data }) => {
console.log("data dans index");
console.log(data);
return data;
});
},
async login({ commit }, user) {
await axiosClient.get("/sanctum/csrf-cookie");
return axiosClient
.post("/api/login", user)
.then(({ data }) => {
commit("SET_USER", data);
commit("SET_AUTHENTICATED", true);
//commit("setAuth", true);
return data;
})
.catch(({ response: { data } }) => {
commit("SET_USER", {});
commit("SET_AUTHENTICATED", false);
});
},
Could somebody help me making out what is wrong or missing?
Edited after Suben's response
I read from somebody that the trouble in Chrome could come from the domain being localhost instead of http://localhost in sanctum config.
Thus I did that and could manage to login with both browser. The trouble is that even with a satisfactory answer to login and the reception of the csrf-token now in both browser the store state is not set despite the answer in the .then function being a valid user object.
Moreover, doing 3 similar requests after that strange situation, the 3 of them being under the auth:sanctum middleware, the first failed with csrf-token mismatch, the second succeeded and the third failed also with csrf-token mismatch. Looking at the requests, they have exactly the same 3 cookies including one with the csrf-token.
My guess is, that RESTful APIs are stateless. That means, they do not worry about sessions. https://restfulapi.net/statelessness/
As per the REST (REpresentational “State” Transfer) architecture, the server does not store any state about the client session on the server-side. This restriction is called Statelessness.
When you login a user with Laravel's SPA authentication, then you ARE storing client session data on the server-side.
So you have two options:
You are moving the endpoint /api/login to web.php (logout too!) OR...
You are using the API token based login.
EDIT:
I had my problems at first too with Laravel Sanctums SPA authentication and Vue. There is a video, which goes through a lot of cases, that might help you aswell for the future (Configuration of cors.php and more): https://www.youtube.com/watch?v=It2by1dL50I
I'm integrating Azure AD and MS-Identity on a web app with Angular.
It works on my machine, but when I deploy it, I get an issue with the callback URL.
First, to make sure the callback URL is ok, I extract it from the microsoft login popup window's URL:
Then, I url decode the content. The URL seems fine and it is available in my Azure app's redirect URL.
Then I login to Microsoft normally and I get this error (AADSTS50011):
Then I inspect the URL again (inside the query string from the urldecoded popup window's URL) and now the URL seems to have been "tampered with".
It's now something like this:
http://somedomain:80/some_page/somequerystring
instead of
https://somedomain/some_page/somequerystring
so I wonder if it's part of the problem or if it's normal behavior.
It is also mentionned "If you contact your administrator, send this info to them." I suppose I'm the "administrator" so what can I do with that "Copy info to clipboard" info to investigate the problem?
Is your application hosting on http (80) or https (443)? If your app service is terminating your TLS connection and handling that for you instead of your app, your sign-on will construct the redirect using the http request scheme. I hooked into the OnRedirectToIdentityProvider event to correct the scheme.
services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
.AddMicrosoftIdentityWebApp(options =>
{
Configuration.Bind("AzureAd", options);
options.Events ??= new OpenIdConnectEvents();
options.Events.OnRedirectToIdentityProvider += _fixRedirect;
});
...
private async Task _fixRedirect(RedirectContext context)
{
context.Request.Scheme = "https";
if(!context.ProtocolMessage.RedirectUri.StartsWith("https"))
context.ProtocolMessage.RedirectUri =
context.ProtocolMessage.RedirectUri.Replace("http", "https");
await Task.CompletedTask;
}
I'm trying to implement Google OAuth 2 signin using FormidableLab's react-native-app-auth library in my react native android application as shown below:
googleLoginPressed = async () => {
const config = {
serviceConfiguration: {
authorizationEndpoint: 'https://accounts.google.com/o/oauth2/v2/auth', tokenEndpoint: 'https://accounts.google.com/o/oauth2/v2/auth',
},
clientId: app_params.GOOGLE_CLIENT_ID, redirectUrl: 'https://<my_domain>/oauth/google',
scopes: ['openid', 'profile', 'email'], additionalParameters: { 'response-type': 'code' },
};
try {
const result = await authorize(config);
} catch (error) {
console.log(error);
}
}
This invokes a web view with Google's signin page and I could successfully authenticate myself. Google then correctly redirects to my oauth callback endpoint and populates the oauth code in the redirect url like it should. At this point, I expect react-native-app-auth to get the control back from the webview to application. Instead, the web view stays open at the redirect url page.
I have added necessary website association configuration under AndroidManifest.xml and the following code under MainActivity.java to check for getting the control back to application from the redirect url:
#Override
public void onNewIntent(Intent intent) { // this is not getting hit
super.onNewIntent(intent);
Uri appLinkData = intent.getData();
if (appLinkData != null) {
bar = appLinkData.getPath();
}
}
What I tried so far
I ensured my app can open Universal links. So website association must be working fine.
Also tried replicating the entire setup on iOS. Same result. The webview shows Google correctly redirecting to oauth endpoint but app fails to get control back.
How do I get control back from oauth web view to my react-native code?
If you are using Claimed HTTPS Schemes, which is the most recommended security option for mobile apps, you are likely to also need an interstitial page after login, that triggers the Universal Link.
My blog post has further info and a code sample you can run, though it uses plain Kotlin rather than React Native.
Background:
I have an angular 7 app.
The app authenticates using Azure Active Directory B2C and Msal for angular
https://github.com/AzureAD/microsoft-authentication-library-for-js/tree/dev/lib/msal-angular
I have created 2 user flow's in AAD B2C:
Signin flow V2
Signup flow V2
both have UI customized,
both contain a redirect button to the other AAD B2C flow.
(from register -> login | from login -> register)
I have setup MSAL module in angular, with Signin flow as the default authority
e.g
MsalModule.forRoot({
...,
authority: <"https://mytenant.b2clogin.com/tfp/mytenant.onmicrosoft.com/B2C_1_Signin">,
...
})
(notice B2C_1_Signin flow name)
This is working well, user can login and register (navigate between flows from within a flow and authenticate).
Problem:
The problem start when I try to manually change the MSAL module authority
(that was defined in MSAL init as B2C_1_Signin flow when app starts).
Example:
User get to a welcome page and can click Login / Register.
If the user clicks login,all is well because the authority link was defined at start as Signin flow (B2C_1_Signin).
If the user would like to register,
I need to change the authority link
to the selected AAD flow (B2C_1_Signup) and then I call MSAL loginRedirect(), user get redirects to right AAD flow, enter his details and redirect back to the app.
Then the app will start a new login flow and redirects to the login flow as if the user is not authenticated.
This only happens when I change the authority link manually (I have no other choice in order to navigate to right flow).
Otherwise, all is working as expected.
How should I change the authority, so the app will not fail the user authentication?
I have tried using default AAD Signup v1 flow with no customization.
I have tried to reveres the process in order to isolate the problem (setup Signup flow as default,
change authority manually to Signin flow, same error (as expected).
I have searched many different sites and forums but none have the same issue or a fix.
https://github.com/AzureAD/microsoft-authentication-library-for-js/issues/498
https://medium.com/#sambowenhughes/configuring-your-angular-6-application-to-use-microsoft-b2c-authentication-99a9ff1403b3
and many more...
MSAL for angular setup:
"authentication.module.ts"
MsalModule.forRoot({
clientID: "<my-client-id>",
authority: "https://tenant.b2clogin.com/tfp/tenant.onmicrosoft.com/B2C_1_Signin",
redirectUri: "http://localhost:4200/dashboard",
/* default is true */
validateAuthority: false,
/* Defaults is 'sessionStorage' */
cacheLocation : "localStorage",
/* Defaults is 'redirectUri */
postLogoutRedirectUri: "http://localhost:4200/",
/* Ability to turn off default navigation to start page after login. Default is true. */
navigateToLoginRequestUrl : false,
/* Show login popup or redirect. Default:Redirect */
popUp: false,
})
AuthService wrapping MSAL auth service:
"auth.service.ts"
constructor(private msalService: MsalService) {}
public login(scopes: string[] = null, queryParams: string = null): void {
this.msalService.authority = this.tenantConfig.baseURL + "/" + this.tenantConfig.tenant + "/" + this.tenantConfig.signInPolicy;
this.msalService.loginRedirect(scopes, queryParams);
}
public signup(scopes: string[] = null, queryParams: string = null): void {
this.msalService.authority = this.tenantConfig.baseURL + "/" + this.tenantConfig.tenant + "/" + this.tenantConfig.signUpPolicy;
this.msalService.loginRedirect(scopes, queryParams);
}
I expect the Msal module to work as usual even if I change the initial defined authority.
Have you tried submitting an issue against the MSAL GitHub library? The issues section for MSAL.JS can be found here : https://github.com/AzureAD/microsoft-authentication-library-for-js/issues
There's actually an ongoing issue on trying to change authority during runtime per the issue here : https://github.com/AzureAD/microsoft-authentication-library-for-js/issues/784
As it's not exactly the same, I suggest filing a new github issue. However it looks like this is not a supported feature as of yet.
We had a similar problem with our application. The fix was essentially turning off MFA.
If MFA is turned on for sign-in, switching from sign-up to sign-in wasn't giving us an MFA prompt and unceremoniously did not authorize the user to be signed in.
Our solution was to detect if the sign in was attempting directly after a sign up and have a non-MFA sign in flow for that case specifically. Not sure if you're doing MFA, but if you are it's worth a look.
I am trying to connect my users with my back end server , i used the example from the official google sign in plugin for flutter :
https://pub.dartlang.org/packages/google_sign_in
the sign process goes fine and i get the username and email ect..
but i need the id Token to authenticate the user with my server.
Ps: Not using firebase , only google sign in.
Can anyone guide me how to get the id Token ?
You can try using this
_googleSignIn.signIn().then((result){
result.authentication.then((googleKey){
print(googleKey.accessToken);
print(googleKey.idToken);
print(_googleSignIn.currentUser.displayName);
}).catchError((err){
print('inner error');
});
}).catchError((err){
print('error occured');
});
You can get access token and id token more simple like this:
final result = await _googleSignIn.signIn();
final ggAuth = await result.authentication;
print(ggAuth.idToken);
print(ggAuth.accessToken);
Or you also can add it to try-catch to handle an error.
try {
final result = await _googleSignIn.signIn();
final ggAuth = await result.authentication;
print(ggAuth.idToken);
print(ggAuth.accessToken);
} catch (error) {
print(error);
}
or try like this if id token was null, it worked for me.
As the docs point out you need oauth2 client id of your backend to request idToken or serverAuthCode.
from firebase google sigin in authentication copy the Web SDK configuration
add paste in the following to res/values/strings.xml, That should work
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="default_web_client_id">{Web app Client id goes here}</string>
</resources>
The issue may be related to not using firebase. There is a google-services.json file which is given to you when you register your app in firebase, and you can use that with google_sign_in (this is the default way shown in the documentation).
I was getting null for the token value when trying to implement this without the google-services.json, but successfully signing into google.
If you don't want to use firebase, you have to jump through a couple hoops.
In google cloud console, register your app.
Then make sure you are 'in' your app that you just created in the top drop down menu.
in "apis and services" in the sidebar menu, go through the create Oauth consent screen menu, I don't remember having to fill out many fields, so leave them blank if you don't know what to put in.
then go to the "credentials" menu in the sidebar, and click "Create New Credentials", and select OAuth2 client ID. Make a web client, even though you're trying to use it with an android/ios app.
Make a file android/app/src/main/res/values/strings.xml
using the web client we just made, insert <?xml version="1.0" encoding="utf-8"?> <resources> <string name="default_web_client_id">YOUR WEB CLIENT ID</string> </resources> into the strings.xml file.
[edit] make one more client in the google console for android, and put in your local machine's sha1 key. This step is done for you automatically if you're using firebase. In this case, you have to create both the web client and one for your android device. In production, you'd be using a specific client for your production app.
That should do it I believe, might have missed a step.
I also wanted to verify on my backend that the incoming idtoken was valid, so I had to also make a service account (in the apis and services -> credentials page) and use that in my go server.
I'm still struggling to get this to work with ios, but the android side works great.
To retrieve the Is idToken worked for me:
1. The google-services.json file must be placed in /android/app/
2. you need to add to your /android/app/build.gradle
apply plugin: 'com.google.gms.google-services'
3. and to /android/build.gradle
classpath 'com.google.gms:google-services:4.3.4'
And that's it. GoogleSignIn will return a real idToken instead of null.
font: https://github.com/flutter/flutter/issues/12140#issuecomment-348720774
One more clean way to achieve this:
late Map<String, dynamic> userObject = {};
var res = await _googleSignIn.signIn();
var googleKey = await res!.authentication;
userObject.addAll({
'accessToken': googleKey.accessToken,
'idToken': googleKey.idToken,
'displayName': res.displayName ?? '',
'email': res.email,
'id': res.id,
'avatarUrl': res.photoUrl ?? '',
'serverAuthCode': res.serverAuthCode ?? '',
});
I was struggling with this issue for about a month. Turns out I was getting the same access token, even when the user tried restarting the app. This was painful because my app dealt with scopes and in case a user misses to check one or more scopes in his first sign in, the app wouldn't work at all, even if he/she signs in again and gives the permissions.
Workaround which worked for me: I called the googleSignIn.currentUser.clearAuthCache() method followed by googleSignIn.signInSilently(). This returns a GoogleSignInAccount which can be used for further authentication. My guess is that the clearAuthCache() method clears the token cache and hence a new token is created. This should get you a new access token and let your app make valid calls.
I sincerely request Google developers to solve this issue. For now, this workaround is the only thing that worked.
Try this:
When you create your GoogleSignIn object:
GoogleSignIn(
clientId: "YOUR CLIENT ID"
)
i hope it helps ;)