getUserIdentityTokenAsync returning expired token - outlook-addin

I'm developing a Mail add-in for composing emails in Outlook 365. The Javascript web app calls getUserIdentityTokenAsync() to obtain an identity token, which is then validated with the app's C# backend web service. The identity token validation in the service is based almost entirely on this sample.
On Wednesday last week I put up the app on a test server for a demo, and it worked as expected. This week when I go to use it I get this exception:
I tried logging out and logging back in but the error persists: why and how is this remedied?
EDIT:
I have caught it in the debugger, it's doing what it's supposed to, I just have to do some digging into why I'm getting these time values:
I guess judging by these values I can just increase the padding... but idk why it would work previously and not now??
EDIT2:
And now that I've updated the padding to be 10 minutes, I actually get back a legit claim that would've worked with the old code, but why the huge discrepancies between the "validFrom" and "now" times? It looks like they're not consistent, like the "validFrom" time fluctuates between ~5-10 minutes ahead or behind the current time.

It looks like the sample throws this error if the nbf claim in the token is later than they think it should be. How does the time in the error compare with the current time? I'm not sure if this is a bug in the sample or an issue with the token.

Related

Service settings

I have a service, written in VB, with some user settings. Two of these are an oauth access / refresh token, and I need to keep storing the new token, so whenever that is updated, I write the settings away again.
Can anyone tell me where those settings are stored on my PC? I can see that the app.exe.config file is not being updated, and it's not being read when I start the service. I don't have a folder in users\username\appdata\local for the service name, nor in roaming, nor in locallow.
I tried using installutil to uninstall and re-install my service, hoping that might cause it to use the settings in app.exec.config, but it did not, it's still trying to use a token that's long out of date from somewhere.
If I paste a new token pair into my app.exe.config, I can see that the service is not reading it. It is reading an old token from when I was last working on it / testing it, and getting an expiry error because I've used a new token pair in a desktop test version of the app.
I seem to be going round and round in circles trying to find where these settings are stored. The annoying thing is that I've had it working, and "sometimes" it will pick up the new token and everything works. But I soon need to install it on the customers PC, and I'm concerned that I'll have another fruitless morning of it using old tokens and not being able to renew them. I'm sure this is something I just don't understand, but I'd rather not go to storing them in a local file if I don't have to. The first answer that comes up on here reveals that others have similar issues and generally resort either to their own storage or the registry, but it is an 11-year-old answer. I'm using VS 2019, if that makes any difference.
This is the code I use to store the new token away, if it helps:
My.Settings.RefreshToken = newToken ' this is returned in the refresh request
My.Settings.Save
When my code opens, it loads the settings in a similar way:
accessToken = My.Settings.AccessToken
refreshToken = My.Settings.RefreshToken
tokenExpires = My.Settings.Expiry
Even if I edit my app.exe.config file to contain "*" in the expiry field, it is still somehow finding the expiry date/time from the previous time the service successfully ran. So it clearly isn't retrieving the information from that file any more.
To close this off, the comment by #Jimi earlier on held the key. The settings that are updated by the service are stored in a file called user.config which in my case is in c:\windows\syswow64\config\systemprofile\appdata and then my application name.

Localhost API for TD Ameritrade

I was creating an API for TD Ameritrade (my first time creating or dealing with APIs) and I needed to put in my own call back URL. I know that callback URL is where the API sends information to and i heard that I can just use my localhost API. I scoured the internet and I dont know how that would work and I was wondering if i can just use http://localhost?
Sorry if I seem like a noob because I am
In short, yes.
Follow the excellent directions at
https://www.reddit.com/r/algotrading/comments/c81vzq/td_ameritrade_api_access_2019_guide/. (Even with them, I spent excessive time on trial and error!)
Since stackoverflow has a limit of 8 links in a response, and the localhost text string looks like a link, I’m showing it with the colon replaced by a semicolon, i.e., http;//localhost to reduce the link count. Sorry.
I used the Chrome browser after first trying Brave, which did not work for, possibly because of my option selections.
Go to https://developer.tdameritrade.com/user/me/apps
Add a new app using http;//localhost (delete existing app if there is one).
Copy the resulting consumer key text string (AKA client_id or OAuth User ID).
Go to https://developer.tdameritrade.com/content/simple-auth-local-apps, follow instructions. Note: leading/trailing blanks were inserted by MSWord due to copy/paste of the auth code, which had to be manually deleted after wasting excessive time identifying the problem. The address string looks like:
https://auth.tdameritrade.com/auth?response_type=code&redirect_uri=http%3A%2F%2Flocalhost&client_id=ConsumerKeyTextString%40AMER.OAUTHAP
This returns a page stating the server refused to connect, but the address bar now contains a VeryLongStringOfCharacters in the address bar:
https;//localhost/?code= VeryLongStringOfCharacters
Copy the contents of the address bar, go to https://www.urldecoder.org/, decode the above, and extract the text after “code=”. This is your refresh_token
Go to: https://developer.tdameritrade.com/authentication/apis/post/token-0, fill out the fields with
grant_type=authorization_code
refresh_token=<<blank>>
access_type=offline
code=RefreshTokenTextString
client_id=ConsumerKeyTextString#AMER.OAUTHAP
redirect_uri=http://localhost
Press SEND.
If the resulting page starts with HTTP/1.1 200 OK, you have succeeded.
Try updating your redirect to:
redirect_uri=https://localhost
They may require https now and you need a colon instead of a semicolon. Everything looks correct. This process generally takes me more then one attempt, and 15 minutes to an hour to get my refresh token squared away every 90 days.
dont use #AMER.OAUTHAP in client_id
If you generate a new code and based on that try to get a new access token. it should work.

LinkedIn authentication stopped returning formatted picture

My app uses LinkedIn authentication along with a couple of other social network logins.
Even though authentication is working fine, all of a sudden LinkedIn stopped returning the formatted profile picture i.e. picture-url. I do however continue to receive the original image i.e. picture-urls -- see below:
In my authentication request, I request r_basicprofile and r_emailaddress and according to this link, I should be receiving both the formatted and the original image.
https://developer.linkedin.com/docs/fields/basic-profile
Up until 10 days ago or so, I was receiving both images. I didn't make any changes to my code but for some reason, the formatted image doesn't show up anymore. Any idea why and how to fix this?
UPDATE:
All of a sudden I started getting both images again -- without making any changes to my code.
I also noticed that the image URL has now changed and I'm seeing all types of parameters in there -- such as image size, something that looks like API version type (alpha in the example below) and possibly a time stamp indicator:
https://media.licdn.com/dms/image/{image-id}/profile-displayphoto-shrink_100_100/0?e=123456789&v=alpha&t={sometypeofid}
I don't remeber seeing any of these parameters in the image URL which is not a URL at all but what seems to be an API call that returns an image.
I don't know if LinkedIn announced such changes that I missed or just decided to make these changes without keeping developers in the loop. I hope it's not the latter and I simply missed the announcement.

How to propagate data from mod-auth-external authenticator to served page

Background
In our Apache configuration we use mod-auth-external (previously on Google Code) to invoke PAM authentication.
Now there is a request for proper handling of shadow-based password expiration:
If password is before warning period Apache should respond with HTTP status code 200. Nothing new here.
If password is in warning period (its validity end is near) Apache should respond with HTTP status code 200, but include somehow information about the warning period.
If password is in expiration period (it is no longer valid but user can still change it on his own) Apache should respond with HTTP status code 401 and include somehow information about expiration period.
If password is beyond expiration period (it is no longer valid and account was locked, administrator must unlock it) Apache should respond with HTTP status code 401 and include somehow information about the locked state.
(There are also corner cases of page missing or some other errors. It is not clear what to do then. But it seems that solving above points would allow to solve those corner cases as well.)
Our PAM authenticator (used through mod-auth-external) is able to differentiate those cases by adjusting return values. That we already have.
The problem is however how to get information from the authenticator to the associated action serving the page (either actual page with 200 status code or 401 error document).
Current investigations
It should be noted that there is significant difference between requirement 2 and requirements 3 and 4.
Requirements 3 and 4 alone are somewhat easier because they both involve our mod-auth-external authenticator returning error (access denied). So we only need to know how to get that error code in 401 error page. I even raised issue on that on mod-auth-external page.
Requirement 2 is much more difficult. In that case our authenticator must return 0 (access granted) and still somehow propagate information about the warning to whatever gets served in the end.
Logs parsing
Obvious (and ugly) idea is to parse logs. mod-auth-external description on Google Code Wiki mentions that authenticator return value gets written to Apache syslog. Also whatever authenticator prints to standard error stream gets logged as well.
This could be used to pass information from authenticator to some other entities.
The difficulty here is that it is not clear how to do it safely. What to print to be sure that "the other entity" will match properly current request with log entry. Mere URL doesn't seem to be enough since there can be multiple requests for the same URL at the same time. While I don't see anything more useful in what authenticator gets.
Another issue here is that it seems that to be able to parse the logs you have to have some non-trivial code running for "the other entity". And this complicates things further since how should we do it?
Another idea
If we could make the authenticator somehow modify "request session" (or whatever, maybe just environment? - I don't know, I'm new to Apache) to add arbitrary data to it we would be (almost) at home.
Our authenticator would somehow store "password status" and also possibly days remaining to the end of warning/expiration period (if applicable). Then upon serving 401 error page we would retrieve that back and use it to dynamically generate content of the page.
Or even better we would have it stored in session so that the other end could read that data directly. (For cases where it is not simply a browser showing page.)
But so far I fail to see how to do that.
Do you have any idea how to meet those requirements?
For over a month I got no answer here. Nor on GitHub issue that I opened for mod-auth-external.
So I ended doing a custom modification to our mod-auth-external. I don't like modifying third party software but this one seems dead anyway. And also it turned out we are using pretty old version (2.2.9 which I upgraded to 2.2.11, the last in 2.2.x line). Which already had some customizations anyway.
I explained details of the solution in a comment to my GitHub issue so I will not repeat them here.
I will however comment on shadow details as they were not mentioned there.
I had two choices: either use getspnam function to retrieve shadow data or to parse messages generated by PAM. First attempts based on getspnam function but in the end I used PAM messages. I didn't have strong reasons for any of those. However I decided to propagate in HTTP response not only shadow status but any PAM message that was generated and so it seemed easier to follow that way.

Why Two Factor Authentication GeneratePin the wrong code?

I've implemented the code from http://satalketo.com/2013/09/mvc-two-factor-authentication/
Two Factor Authentication in ASP.NET MVC
when user register he gets a Secret Key and shown a QRcode he can scan to Google Authenticator,
all works fine and well, accept when the user tries to Log In the system the key always different from the one he enters. function GeneratePin at server side generate different key from that he gets in the Google Authenticator mobile app. I have no idea whats wrong, tried to think maybe time zone isn't correct ,my time zone is Jerusalem UTC + 2
I've looked through my code a fair bit and I can't see any reason why this should be an issue. The only reason that I can come up with is that one of the two devices is more than 30 seconds out of sync with UTC.
I have updated the source code to include checking against the 30 second periods either side of the current one to try and deal with any situations like that.
You can find the updated code on GitHub, which would be the best place to download the entire solution. My article Two Factor Authentication in ASP.NET MVC has been updated to include the code for checking the period either side.
If this doesn't help please let me know with any additional information you can think of.