I've been able to authenticate multiple Twitter accounts for months now, however I just changed my app's permissions to allow DM viewing. After that I reauthentiacted my accounts and the first one worked fine, but any additional account did not.
I decided to print out the consumer key, consumer secret, access token and access token secret to the console. For the my first account there are no spaces and they look correct. However the second account's access token is 10 characters longer than any of the access tokens before I allowed direct messages. Also whenever I attempt to authenticate I get this error:
400:The request was invalid. An accompanying error message will explain why. This is the status code will be returned during version 1.0 rate limiting(https://dev.twitter.com/pages/rate-limiting). In API v1.1, a request without authentication is considered invalid and you will get this response.
message - Bad Authentication data.
code - 215
According to the error message and some google searches it seems like this error is ran whenever a request is made without authenticating. However I am authenticating. Also whenever I change the keys in any way it gives me a completely different error about invalid or expired tokens (error 89).
This only happens with additional accounts, and not the first account I authenticate (the first account works perfectly, as expected). This is the code I'm running:
public class Tweeter {
private String consumerKey = null;
private String consumerSecret = null;
private String accessToken = null;
private String accessSecret = null;
private Twitter twitter = null;
public Tweeter(String consumerKey, String consumerSecret, String accessToken, String accessSecret) {
this.consumerKey = consumerKey;
this.consumerSecret = consumerSecret;
this.accessToken = accessToken;
this.accessSecret = accessSecret;
ConfigurationBuilder cb = new ConfigurationBuilder();
cb.setOAuthConsumerKey(consumerKey).setOAuthConsumerSecret(consumerSecret).setOAuthAccessToken(accessToken).setOAuthAccessTokenSecret(accessSecret);
TwitterFactory factory = new TwitterFactory(cb.build());
twitter = factory.getInstance();
Logger.log("\"" + factory.getInstance().getConfiguration().getOAuthConsumerKey() + "\"");
Logger.log("\"" + factory.getInstance().getConfiguration().getOAuthConsumerSecret() + "\"");
Logger.log("\"" + factory.getInstance().getConfiguration().getOAuthAccessToken() + "\"");
Logger.log("\"" + factory.getInstance().getConfiguration().getOAuthAccessTokenSecret() + "\"");
}
public String getConsumerKey() {
return consumerKey;
}
public String getConsumerSecret() {
return consumerSecret;
}
public String getAccessToken() {
return accessToken;
}
public String getAccessSecret() {
return accessSecret;
}
public Twitter getTwitter() {
return twitter;
}
}
This is the same code I've used in the project I'm working on for months now, even with some of the same additional Twitter accounts. The only thing that changed is the app permissions now allow me to view DMs. Any ideas how I can get this working again? Thanks
The problem is solved. Not sure why this was happening but I tried to reauthenticate additional accounts and it works now. Not sure if there was a problem on Twitter's end or what, I do not believe that I've changed any of the code that was affecting this system in any way.
Related
We're writing end to end tests with protractor for an application written in Angular. The app authenticates via Azure AD using the ADAL library.
Currently we click through the AzureAd sign in process using WebDriver before the tests start, but this is fragile. We had issues with the Microsoft password login screen not loading at all. Also the login process locally can get complicated because it takes our Windows credentials sometimes and sometimes it doesn't.
Looking for alternatives, is it possible to generate either:
An idtoken in the protractor start up process (onPrepare) through some node library (like passport?) from Azure Ad directly? That I can later set for the tests to use.
Some sort of forever living static bearer idtoken that the e2e tests read from a config file?
Is there any other approach I could be missing?
You can use the ROPC flow to acquire tokens for tests.
This is one of the cases where using this flow can be ok in my opinion.
Using it to bypass the login screen in a normal app is not okay.
It also doesn't work with all kinds of users, federated users can sometimes work, depending on how it's setup.
Here is what I've used:
// _authority = e.g. https://login.microsoftonline.com/company.com
string tokenUrl = _authority + "oauth2/v2.0/token";
var req = new HttpRequestMessage(HttpMethod.Post, tokenUrl)
{
Content = new FormUrlEncodedContent(new Dictionary<string, string>
{
["grant_type"] = "password",
["client_id"] = settings.ClientId, // client id for your app
["client_secret"] = settings.ClientSecret, // client secret for your app
["scope"] = $"openid profile {_resourceUri}/.default", // here you define what you want tokens for
["username"] = settings.UserName,
["password"] = settings.Password
})
};
HttpResponseMessage res = await _client.SendAsync(req);
string json = await res.Content.ReadAsStringAsync();
AadTokenResponse tokenResponse = JsonConvert.DeserializeObject<AadTokenResponse>(json);
// tokenResponse.IdToken contains the ID token
// The AadTokenResponse class:
class AadTokenResponse
{
[JsonProperty("access_token")]
public string AccessToken { get; set; }
[JsonProperty("id_token")]
public string IdToken { get; set; }
}
The scope is where you must specify at least the openid scope in order to get an ID token.
Here I have also specified an API app ID URI + "/.default" to get an access token for an API.
You can keep the scope as openid profile if you only need the id token.
Keep in mind that you will then need to secure app credentials and user credentials in your test configuration.
Also, I recommend that these credentials are not for a production environment.
You may need to create cloud-only user accounts for them to work properly.
Also the user accounts cannot have MFA enabled.
If their password expires, you'll need to set a new password and update your test config.
I am using OAuth2.0 to connect to Exchange webservices. Everything else seems to work ok for me . However when i try to subscribe one of the room resource by using grouping info and providing the anchor mailbox as one of the primary mail box it throws an error.
"Request failed because EWS could not contact the appropriate CAS server for this request."
So for example i am trying to subscribe nitroom1 and one the primary mailbox associated with the group is nitroom2 which i am using as X-AnchorMailbox then i got the above error.
public static ExchangeService GetExchangeService(string exchangeURL, string userName, string password, string resourceEmail, string primaryMailbox, string clientID, string tenantID, string clientSecret, string certName)
{
ExchangeService service;
service = new ExchangeService(setTZtoUTC);
service.Url = new Uri(exchangeURL);
if (!string.IsNullOrWhiteSpace(clientID) && !string.IsNullOrWhiteSpace(tenantID))
{
string oAuthToken = multiExchangeManager.getOAuthTokenFromCache(clientID, tenantID, clientSecret, certName);
service.Credentials = new OAuthCredentials(oAuthToken);
}
else
{
service.Credentials = new WebCredentials(userName, password);
}
service.ImpersonatedUserId = new ImpersonatedUserId(ConnectingIdType.SmtpAddress, resourceEmail);
service.HttpHeaders.Add("X-AnchorMailbox", primaryMailbox);
service.HttpHeaders.Add("X-PreferServerAffinity", "true");
return service;
}
However if i connect ews using impersonate account then do same thing it works fine.
Also, if i use resourceMailbox same as primary mailbox then it works ok as well.so in my example it will look like this.
service.ImpersonatedUserId = new ImpersonatedUserId(ConnectingIdType.SmtpAddress, "nitroom1");
service.HttpHeaders.Add("X-AnchorMailbox", "nitroom1");
This is how i am trying to use subscription.
exchangeService.SubscribeToStreamingNotifications(
new FolderId[] { WellKnownFolderName.Calendar, WellKnownFolderName.DeletedItems },
EventType.Created, EventType.Deleted, EventType.Modified, EventType.Moved, EventType.Copied);
Does anyone have any idea why its happening or what i am doing wrong here?
one more thing to add, i tried EWSEditor tool which provides subscription info and both above mentioned resources sharing same grouping info.
I think i found a solution for this issue, i just need to set
X-BackEndOverRideCookie with any service used for subscribing child mailbox.
For more info read this article
https://learn.microsoft.com/en-us/exchange/client-developer/exchange-web-services/how-to-maintain-affinity-between-group-of-subscriptions-and-mailbox-server
In our website we used to use access_token when logging people with Google Sign In. First, we redirect the user to google, user brings the access_token to us, and we validate that token to make sure the user is the actual Google user.
Then, we needed a Google sign-in feature for our Android app, so I wanted the Android developer to bring access_token to us. He replied he couldn't. I searched about that finding almost no documentation about access_token. In documentation, Google says me to use the "id_token".
OK, I wanted the developer to bring me the id_token, and I have successfully verified the token's integrity. Then I wanted to implement the same for websites.
My c# code is:
string googleId = GoogleJsonWebSignature.ValidateAsync(idToken).Result.Subject;
It worked when I ran it locally, but when I tried in production, it gave an error: JWT is not yet valid
Is id_token the correct way to send to the backend and verify? I found another option too: code.
Code is something like A/12112312......
Access_token is something like ya29.somemorestring
My question is, Which one is correct to send to the backend? By the way, I think access_token is sort of deprecated or something like that.
Yes, you should be using the id_token. You get the id_token on the client side using this:
var id_token = googleUser.getAuthResponse().id_token;
and validating it on the server side using (do in a try/catch block to catch any errors):
token = await GoogleJsonWebSignature.ValidateAsync(idToken);
The JWT is not yet valid error is due to the time on your server being slow. Even a few seconds slow will cause this problem. To be sure of this working all the time, you'll need to implement a custom clock which gets an accurate time from somewhere. Here's an example using NNTP:
public class AccurateClock : Google.Apis.Util.IClock
{
const int UpdateIntervalMinutes = 60;
const string NntpServer = "time.nist.gov";
private TimeSpan _timeOffset;
private DateTime _lastChecked;
public AccurateClock()
{
_timeOffset = TimeSpan.FromSeconds(0);
_lastChecked = DateTime.MinValue;
}
private DateTime GetTime()
{
try
{
if (DateTime.Now.Subtract(_lastChecked).TotalMinutes >= UpdateIntervalMinutes)
{
// Update offset
var client = new TcpClient(NntpServer, 13);
DateTime serverTime;
using (var streamReader = new StreamReader(client.GetStream()))
{
var response = streamReader.ReadToEnd();
var utcDateTimeString = response.Substring(7, 17);
serverTime = DateTime.ParseExact(utcDateTimeString, "yy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal);
}
_timeOffset = DateTime.UtcNow.Subtract(serverTime);
_lastChecked = DateTime.Now;
}
var accurateTime = DateTime.UtcNow.Subtract(_timeOffset);
return accurateTime;
}
catch (Exception ex)
{
return DateTime.UtcNow;
}
}
public DateTime Now
{
get
{
return GetTime().ToLocalTime();
}
}
public DateTime UtcNow
{
get
{
return GetTime();
}
}
}
You then pass the custom clock to the validation method.
token = await GoogleJsonWebSignature.ValidateAsync(idToken, new AccurateClock());
Please note: This will update the difference between the correct time and the local machine time every time the class is created, so you really want to register this as a Singleton in whatever IOC container you are using and pass the reference to the validator instead. It will then recheck the time using NNTP every hour. If you are not using an IOC Container you could make the class static.
id_token is a JWT token, that you validate and extract information such as "email", "name" etc. This is actually what you need in a regular case.
code and access_token are part of the flow when a user doesn't use your app in current moment but your app wants to make any actions behalf of them. Google calls it offline access https://developers.google.com/identity/sign-in/web/server-side-flow
I am making the api calls through the controller action method as below. The following is the working code of it.
But I want to secure the webapi so that only my application can access it. I have seen sources with login credentials
but in my case it is a public facing website with no login users.
Only the calls from my application should access it. Could anyone please suggest what can be done. or Is my current code with ValidateReferrer is suffice to handle?
[HttpGet]
[ValidateReferrer]
[ActionName("GetFind")]
[CacheOutput(ClientTimeSpan = 300, ServerTimeSpan = 300)]
public ApiQueryResponse GetFind(string query)
{
return _Worker.GetFind(query);
}
Validate Referrer in the controller has the following implementation:
public override void OnAuthorization(AuthorizationContext filterContext)
{
if (filterContext.HttpContext == null)
{
throw new System.Web.HttpException("No Http context, request not allowed.");
}
else
{
if (filterContext.HttpContext.Request.UrlReferrer == null)
{
throw new System.Web.HttpException("Referrer information missing, request not allowed.");
}
else if (filterContext.HttpContext.Request.UrlReferrer.Host != filterContext.HttpContext.Request.Url.Host)
{
throw new System.Web.HttpException(string.Format("Possible cross site request forgery attack, request sent from another site: {0}", filterContext.HttpContext.Request.UrlReferrer.Host));
}
}
}
In the worker class,
public ApiQueryResponse GetFind(string query)
{
var results = GetResults(Settings.ApiKey, SetFindParameters(query), Resource);
return results;
}
private ApiQueryResponse GetResults(string apiKey, string parameterQuery, string Resource)
{
var results = new ApiQueryResponse();
if (apiKey != null && !String.IsNullOrWhiteSpace(apiKey))
{
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
var response = client.GetAsync(string.Format("{0}/{1}?{2}&key={3}", WebApiUrl, Resource, parameterQuery, apiKey)).Result;
if (response.IsSuccessStatusCode)
{
var responseBodyAsText = response.Content.ReadAsStringAsync().Result;
results = JsonConvert.DeserializeObject<ApiQueryResponse>(responseBodyAsText);
}
}
}
return results;
}
Again this is the case where you have to authenticate your "application" but not users. If you check facebook/twitter/gmail api's, they have a client secret and client id to authenticate the application. But still there will be an "Authorize" call made with this id and secret for which the api returns a token and this token is used henceforth to authorize the other requests. This token will also have an expiry and there are methods to get refresh tokens.
Thus said, you have to take a call on how much security you have to implement for your api's. You could have a similar approach where your client first asks for a security token by providing the client id and secret (which should really be a secret). You can check this id and secret against your store (may be database) and if that passes the validation, you can send back a token which you could authroize using [Authroize] attribute or by custom validation.
How to create tokens should be another discussion IMO. Simple approach is mentioned here for eg- how to generate a unique token which expires after 24 hours?. There are other standard ways of generating tokens JWT/OAuth tokens.
EDIT
As a simple approach (not taking much security aspects into consideration) would be:
Create an app secret (may be a Guid value)
While sending request, take current timestamp and encrypt (have your
own encrypt and decrypt logic) the timestamp with the app secret. Lets call that encrypted value as 'token'
Pass the token in your request header (may be a custom header,say,
x-my-auth)
In the api, have a custom authorize filter
In the custom filter, overridden OnAuthroizeCore method, get the
token from request header
Decrypt the token using the same app secret and you will get the
timestamp sent from the client
If decryption is fine, then we are through the first step/ or the
token passed the first step
Additionaly, check whether the difference between the current time
and the time decrypted from token is more than 5(*you can have your
own expiry value)
If the difference is more than your expiry limit, return false which
would throw unauthorized exception back to the client (do the same if the token fails to decrypt)
The expiry check is to handle the scenario where someone hacking your
token from the request and then using it afterwards. In case if he
uses the token after your expiry, this would throw unauthorized
Consider the above logic and entire description just as a "food for thought" and DO NOT use it without proper research and understanding. My idea was to give some basic idea about the application authentication until someone really good at this writes up a really nice article in this post
I'm trying to implement OAuth with twitter so my users can log into my site using their Twitter IDs. For this I am using the TweetSharp library. Following the examples they have I wrote the following code which seems to work.
public ActionResult Login(string oauth_token, string oauth_verifier)
{
var service = new TwitterService(consumerKey, consumerSecret);
if (oauth_token == null)
{
var requestToken = service.GetRequestToken(Request.Url.ToString());
var uri = service.GetAuthorizationUri(requestToken);
return new RedirectResult(uri.ToString(), false);
}
else
{
var requestToken = new OAuthRequestToken { Token = oauth_token };
OAuthAccessToken accessToken = service.GetAccessToken(requestToken, oauth_verifier);
service.AuthenticateWith(accessToken.Token, accessToken.TokenSecret);
TwitterUser user = service.VerifyCredentials(new VerifyCredentialsOptions());
TempData["response"] = string.Format("Your username is {0}", user.ScreenName);
return RedirectToAction("Success");
}
}
public ActionResult Success()
{
ViewBag.Response = TempData["response"];
return View();
}
However, there is a problem. Every time the user logs into the system twitter asks them to authorize the application even though they have done it before. Is there a way to prevent this behavior? I have also implemented OAuth with Facebook and Google and I don't need to authorize the application every time I want to log into the system.
Unfortunately not as far as I'm aware. Twitter uses OAuth 1.1 rather than OAuth 2.0 like Facebook and Google, so there is a manual step in the middle in which users are asked to authorise the application even though they have done already. I'm having exactly the same issue and it appears to be something we have to live with.
I was having the same problem with a slightly older app I was trying to resurrect. I noticed that the problem went away when I selected "Sign in with Twitter" in my app settings at http://dev.twitter.com/apps.