I am "suddenly" (after an update?) experiencing 2 new issues when authenticating using the ADAL (Microsoft.IdentityModel.Clients.ActiveDirectory) library in my iOS Xamarin application that was previously working fine.
I have tried rolling the version back to what was working previously, or alternatively moving up to the latest stable version but the issues persist. Here is the code I am using.
public async System.Threading.Tasks.Task<AuthenticationResult> Authenticate(string authority, string resource, string clientId, string returnUri)
{
var authContext = new AuthenticationContext(authority);
if (authContext.TokenCache.ReadItems().Any())
authContext = new AuthenticationContext(authContext.TokenCache.ReadItems().First().Authority);
var authResult = await authContext.AcquireTokenAsync(resource, clientId, new Uri(returnUri),
new PlatformParameters(UIApplication.SharedApplication.KeyWindow.RootViewController));
return authResult;
}
The first issue is that when successfully authenticating the library fails to cache the returned token(s). During the call to AcquireTokenAsync() I observe the following output in the Debug window:-
AcquireTokenHandlerBase.cs: === Token Acquisition started:
Authority: https://login.windows.net/xxx.onmicrosoft.com/
Resource: XXXX
ClientId: XXXX
CacheType: null
Authentication Target: User
TokenCache.cs: Looking up cache for a token...
TokenCache.cs: No matching token was found in the cache
TokenCache.cs: Storing token in the cache...
TokenCache.cs: An item was stored in the cache
AcquireTokenHandlerBase.cs: === Token Acquisition finished successfully. An access token was retuned:
It then seems to attempt to write the token to the cache but I see the following in the debug window:-
TokenCachePlugin.cs: Failed to remove cache record: -34018
TokenCache.cs: Serializing token cache with 1 items.
TokenCachePlugin.cs: Failed to save cache record: -34018[0:] Bearer eyJ0eXAiOiJ…
Then the next time I start the application and call this method I observe the following output:-
- AuthenticationContext.cs: ADAL PCL.iOS with assembly version '3.13.9.1126', file version '3.13.9.1126' and informational version 'eddfa8ebda9e734efdc42ea6d41ea98bc7c998f3' is running...
xxxxxxx-7318-4ec7-xxxx-7xxxxxxx42c2 - AcquireTokenHandlerBase.cs: === Token Acquisition started:
Authority: https://login.windows.net/xxx.onmicrosoft.com/
Resource: XXXX
ClientId: XXXX
CacheType: null
Authentication Target: User
TokenCache.cs: Looking up cache for a token...
TokenCache.cs: No matching token was found in the cache
There seems to be no further information around on how to interpret this that I can find? The thing is this code was working fine previously, however I think it has stopped working possibly afer an upgrade to XCode on my mac. I am developing on a Parallels VM with VS2017.
Therefore every time I start the app I need to login again. I have seen this reported elsewhere but have not found a resolution. Is there a clue in the “CacheType: null” output maybe?
The second issue is that the call to AcquireTokenAsync() seems to not return when the user selects “Cancel” on the login screen - ie the “return authResult;” line never gets hit - unless I actually successfully authenticate. Is that expected, or am I maybe using the library incorrectly in both instances?
Related
I am encountering a weird issue with Microsoft Graph on an integration that was built a few years back.
This issue started happening a few months back. After I sync a Microsoft Account and provide email and calendar read/write access, everything works fine for some time. I am able to retrieve emails and calendar events. However, after some time, I notice that when a call is made to GetAccountAsync with a valid AccountID, null is returned. This is causing AcquireTokenSilent to fail with the following error:
Error Code: user_null
Error Message: No account or login hint was passed to the AcquireTokenSilent call.
I have also noticed that this happens under the following scenarios:
When the WebJob (console app) is run every 15 minutes, I encounter this issue
To narrow down the root cause, I have deleted the WebJob to see if the issue occurs on the web app. It looks like the issue starts to occur after an hour or so even without the web job running.
I have upgraded to the latest version of MSAL and implemented 4.46.1.0 version of Microsoft.Identity.Client. I am using .NET Framework 4.8 and this is a .NET MVC 5 app.
Here's my code:
public async Task<string> GetAccessTokenAsync()
{
string accessToken;
UserExternalApp.Scope = string.IsNullOrWhiteSpace(UserExternalApp.Scope) ? "" : UserExternalApp.Scope;
// Load the app config from web.config
var microsoftScopes = UserExternalApp.Scope.Replace(' ', ',').SplitAndTrim(new char[] { ',' }).ToList();
var accountID = UserExternalApp.ExternalUserAccountID;
var app = ConfidentialClientApplicationBuilder.Create(ClientID)
.WithRedirectUri(DefaultRedirectUrl) // https:\//mywebsite.com
.WithClientSecret(Secret)
.Build();
app.AddDistributedTokenCache(services =>
{
services.AddDistributedSqlServerCache(options =>
{
options.ConnectionString = System.Configuration.ConfigurationManager.ConnectionStrings["Connection"].ConnectionString;
options.SchemaName = "dbo";
options.TableName = "TokenCache";
options.DefaultSlidingExpiration = TimeSpan.FromMinutes(90);
});
});
try
{
var account = await app.GetAccountAsync(accountID);
var query = app.AcquireTokenSilent(microsoftScopes, account); // This is where the error is thrown
var acquireTokenSilent = await query.ExecuteAsync();
accessToken = acquireTokenSilent.AccessToken;
}
catch
{
// This is the error thrown:
// Exception Type: MsalUiRequiredException
// Error code: user_null
// Exception Details: No account or login hint was passed to the AcquireTokenSilent call.
throw;
}
return accessToken;
}
I know the token is persisted on my SQL Server:
I think the MSAL uses an in memory token cache by default, Once the client logins, authentication information will be stored in cookie(if cookie has not been disabled). Even your web application restarts, the client will keep logged in.
To solve this, you can use custom Token cache serialization in MSAL.NET:https://learn.microsoft.com/en-us/azure/active-directory/develop/msal-net-token-cache-serialization?tabs=aspnet.
Hope this helps.
I would like to share the resolution to this problem in case if it helps someone in the future. I feel that this is a Microsoft Bug that was introduced during one of their many upgrade process as this code went from working to broken without any change from our end. Here are the steps I took:
While exchanging the code for a token after user authentication, I retrieved and saved Account.HomeAccountId.Identifier, Account.HomeAccountId.ObjectId and TenantId for the account.
I implemented my own version of IAccount.
Instead of calling await app.GetAccountAsync(accountID), I used my implementation of IAccountand initialized it with the data I saved in Step 1.
I used this account to call app.AcquireTokenSilent(microsoftScopes, account).
And that's it! No error was thrown once this was done!
Firebase ID token has invalid signature
Hi all, I'm somehow new to NodeJS and I've only used Google Firebase a few times.
Now, I'm trying to verify an idToken generated using getIdToken() method whenever a user signs up or signs in. The token generation works fine but if I try to use this token to authorize a user admin.auth().verifyIdToken(idToken) on another route, I get this error Firebase ID token has invalid signature on Postman. I tried to verify the token on jwt.io as well, it gave error Invalid Signature.
I tried switching to different algorithms, some eventually made the token valid on jwt, but there is usually a VERIFY SIGNATURE box by the bottom-right which I don't really know what to fill there. Well, I've tried copying different newly generated valid tokens by jwt after changing algorithm, but I still get Firebase ID token has invalid signature from Postman.
Does anyone know what the problem may be? Please help.
The problem comes from the Firebase Emulator Auth. The Firebase-hosted Auth is unable to verify JWT token generated by the Firebase Emulator Auth.
To verify the token manually on jwt.io, you need to grab one of the public keys from google: https://www.googleapis.com/robot/v1/metadata/x509/securetoken#system.gserviceaccount.com
To choose the correct key, find the one that corresponds to your kid from jwt.io.
Paste in the correct corresponding value and now your token should verify correctly (be sure to clear out any \n characters):
For easier programmatic verification, the "JWK URI" is https://www.googleapis.com/service_accounts/v1/jwk/securetoken#system.gserviceaccount.com
Source: https://firebase.google.com/docs/auth/admin/verify-id-tokens
For some reason, verifyIdToken function throws "Firebase ID token has invalid signature" each time for valid tokens when used in Firebase Emulator locally. I fixed this problem by starting using firebase hosted auth instead of emulator auth (remove auth property from firebase.json). Also, I reported the bug to Firebase.
I agree with Genius Hawlah's answer, the problem is the Firebase Emulator Auth. As a workaround I suggest to start emulators without the Auth one with the --only flag, for example firebase emulators:start --only firestore,functions, and authenticate with a user you have in the production Authentication
TLDR;
Prefer log from dart:developer over print and debugPrint.
I was not using the emulator...
I'm new to Firebase and have experienced this, and even upvoted GeniusHawlah's as Taras Mazurkevych's answers... But couldn't find anything in the Firebase setup related to the simulator that I did.
So it happened I was testing my firebase using a truncated JWT token, printed from Dart's debugPrint (which limits truncates output). I was successful in using log from dart:developer!
I was enlightened by https://github.com/flutter/flutter/issues/22665#issuecomment-456858672.
I encountered a similar problem, figured out that by BE was pointing to the local emulator, but FE was pointing to the remote Firebase Auth (because of a bug in the code firebase.auth().useEmulator(...) wasn't called)
As you can see in the source code, the firebase-admin package behaves differently when there is an Auth emulator available. You can either not start it to begin with or make it undiscoverable by removing its address from process.env.
delete process.env.FIREBASE_AUTH_EMULATOR_HOST
Source reference:
public verifyIdToken(idToken: string, checkRevoked = false): Promise<DecodedIdToken> {
const isEmulator = useEmulator();
return this.idTokenVerifier.verifyJWT(idToken, isEmulator)
.then((decodedIdToken: DecodedIdToken) => {
// Whether to check if the token was revoked.
if (checkRevoked || isEmulator) {
return this.verifyDecodedJWTNotRevokedOrDisabled(
decodedIdToken,
AuthClientErrorCode.ID_TOKEN_REVOKED);
}
return decodedIdToken;
});
}
emragins answer is great!
One thing which emragins wrote but it wasn't clear for me is that you need to copy the whole text between
-----BEGIN CERTIFICATE-----
-----END CERTIFICATE-----\n
and made replace("\n","").
The result from this operation you can paste to the JTW.io. VERIFY SIGNATURE field.
i made a Discord bot which was working just fine until recently; since yesterday it's refusing to log in (output says invalid token was provided but creating a new token and putting it into code won't work).
The funny part is I actually have two versions of the same bot (deploy and test where the latter is only in one of my servers where i test new functions before implementing them in the deployed version).
Just replacing the token with the "test-bot" one fix the issue and allows me to correctly login (with the wrong bot of course since I'm using bot-test token).
To verify the token i made this very small script:
client.login(botToken).then().catch(reason => {
console.log("Login failed: " + reason);
console.log("Token used: " + botToken);
}); //login in discord
This allows me, in case of failed login to have similiar output:
Login failed: Error [TOKEN_INVALID]: An invalid token was provided.
Token used: NjAxMzc3Mzg3NDgwODc1MDE4.Xr5Cyg.xhX3QYqk0prPC7y3KS0yc5JA02U
Here you can see a screenshot from discord bot page where you can double-check the token used IS correct (the token now has been reset so this one won't be valid anymore)
I can tell the import method of the token (it's imported from another file) works fine (bot.js can see it and what i actually do when I change version is commenting/decommenting 2 lines of code (containing token and client ID which is used by a bot function).
Additional info:
I'm using Discord 12 at the moment but the bug started yesterday giving out the same result and I had installed discord 11+ back then.
nodejs version used is 12.16.3
npm version used is 6.14.4
bot is hosted in a VPS running Debian 9
Is anyone able to help with this or encountered similiar error?
Thanks in advance,
I'm trying to implement a custom authentication in an Azure Mobile App (not the old Mobile Service) with a Node.js backend, with actions I can't quite translate into Node. An earlier question states that custom authentication "just works" with a .NET backend. I am having trouble getting
I have copied Joy of code's example JWT generation (gist here). I invoke it like this (inlining the aud and userId):
zumoJWT(expiry,"MyAud","MyAud:1455527189540927",req.azureMobile.configuration.auth.secret);
My registration API returns the following JSON
{"user":{"userid":"MyAud:1455527189540927"},"token":"a lot of base64"}
Which I put into the Android MobileServiceClient with this code
JsonObject userob=ob.get("user").getAsJsonObject();
MobileServiceUser user=new MobileServiceUser(userob.get("userid").getAsString());
user.setAuthenticationToken(ob.get("token").getAsString());
mClient.setCurrentUser(user);
Which gives me the error message
com.microsoft.windowsazure.mobileservices.MobileServiceException: {"name":"JsonWebTokenError","message":"invalid signature"
The next time I invoke an API. How do I make my app accept the login token?
Edit: The server-side logs say
2016-02-15T11:42:35 PID[180] Warning JWT validation failed: IDX10500: Signature validation failed. Unable to resolve SecurityKeyIdentifier: 'SecurityKeyIdentifier
(
IsReadOnly = False,
Count = 1,
Clause[0] = System.IdentityModel.Tokens.NamedKeySecurityKeyIdentifierClause
)
',
token: '{"alg":"HS256","typ":"JWT","kid":0}.{"exp":null,"iss":"urn:microsoft:windows-azure:zumo","ver":2,"aud":"MyAud","uid":"MyAud:1455534835642715"}
RawData: a lot of base64'..
I figured it out. I needed to have
mobile.configuration.auth.validateTokens=false;
in app.js (or rather, not have the same variable set to true).
Some context: the user had previously installed the app, authorized FB, everything worked great, then they changed their FB password (through facebook.com), deleted the app, and have now reinstalled it and are running it for the first time again after reinstall.
I am calling [FBSession openActiveSessionWithReadPermissions:allowLoginUI:completionHandler] with allowLoginUI: YES and the read permissions being "email, user_about_me, user_birthday, user_interests, user_location."
The FBSessionState I am getting in the completionHandler is FBSessionStateClosedLoginFailed. The NSLog of the error is this:
Error Domain=com.facebook.sdk Code=2 "The operation couldn’t be completed. (com.facebook.sdk error 2.)" UserInfo=0x1cd68c00 {com.facebook.sdk:ErrorLoginFailedReason=com.facebook.sdk:ErrorLoginFailedReason, com.facebook.sdk:ErrorInnerErrorKey=Error Domain=com.apple.accounts Code=7 "The Facebook server could not fulfill this access request: Error validating access token: The session has been invalidated because the user has changed the password." UserInfo=0x1cd5b970 {NSLocalizedDescription=The Facebook server could not fulfill this access request: Error validating access token: The session has been invalidated because the user has changed the password.}}
That internal error domain is ACErrorDomain and error code ACErrorPermissionDenied. So, how do I let the user re-authorize the app?
I have tried calling openActiveSessionWithReadPermissions again but that just keeps outputting the same error. I have also tried [FBSession.activeSession closeAndClearTokenInformation] but that doesn't seem to do anything (presumably because there is no activeSession).
Hitting a very similar sort of bug with 3.2.1 Facebook SDK. In my case, I get into FBSessionStateOpen but have been given an invalid access token. As the question states, the normal closeAndClearTokenInformation and even deleting the app doesn't fix it. The only way I have been able to get-back-in under this scenario is to have the user change their password in the setting app. So this is what I do.
// In my completion handler FBSessionStateOpen is called BUT an
// invalid accessToken was detected.
[session closeAndClearTokenInformation];
[FBSession renewSystemCredentials:^(ACAccountCredentialRenewResult result,
NSError *error)
{
if (result == ACAccountCredentialRenewResultFailed ||
result == ACAccountCredentialRenewResultRejected)
{
[self showErrorMessage:NSLocalizedString(#"You may need to re-enter your Facebook password in the iPhone Settings App.\n", nil)];
}
else
{
// attempt opening a session again (after they have updated their account
// settings I end up here)
[self facebookLogin]; // Performs openActiveSessionWithReadPermissions,
// but this time around the token issued should be good.
}
}];
This is the only pragmatic solution I have been able to come up with.
I think you need to get a new access token with code like this...
[FBSession.activeSession closeAndClearTokenInformation];
[[FBSession class] performSelector:#selector(renewSystemAuthorization)];
[FBSession openActiveSessionWithReadPermissions:nil
allowLoginUI:YES
completionHandler:^(FBSession *session, FBSessionState state, NSError *error) {
}