Imgur API version 3 uploading examples? - c#

I'm trying to add this functionality to a C# Windows app I have in development, for uploading images to Imgur.
Unfortunately it has to be Imgur, as that site is the requirement.
The problem is that whatever C# example code I can find is old and doesn't seem to work with their version 3 API.
So I was wondering if anyone with expertise in the area can help me out.
I would prefer to upload using OAuth, and not the Anonymous option, but the latter can be used as an example if needed.
EDIT:
One part I especially don't get is how can I make the authorization step happen while remaining within the desktop application. The authorization step requires the opening of a webpage, where the user is asked if they will allow the application to use their data or not.
How can I do this for a Desktop-based app?

Before you start you´ll need to register your Application to recieve a clientID and the client secret. Guess you´re aware of that already. Detailed information can be found on the official Imgur API Documentation.
Regarding authentication you´re right, the user has to visit a webpage and grab and authorize your appication there. You can either embed some Webbrowser control in your Application or simply instruct the user to browse to a webpage.
Here´s some untested Code that should work with little modifications.
class Program
{
const string ClientId = "abcdef123";
const string ClientSecret = "Secret";
static void Main(string[] args)
{
string Pin = GetPin(ClientId, ClientSecret);
string Tokens = GetToken(ClientId, ClientSecret, Pin);
// Updoad Images or whatever :)
}
public static string GetPin(string clientId, string clientSecret)
{
string OAuthUrlTemplate = "https://api.imgur.com/oauth2/authorize?client_id={0}&response_type={1}&state={2}";
string RequestUrl = String.Format(OAuthUrlTemplate, clientId, "pin", "whatever");
string Pin = String.Empty;
// Promt the user to browse to that URL or show the Webpage in your application
// ...
return Pin;
}
public static ImgurToken GetToken(string clientId, string clientSecret, string pin)
{
string Url = "https://api.imgur.com/oauth2/token/";
string DataTemplate = "client_id={0}&client_secret={1}&grant_type=pin&pin={2}";
string Data = String.Format(DataTemplate, clientId, clientSecret, pin);
using(WebClient Client = new WebClient())
{
string ApiResponse = Client.UploadString(Url, Data);
// Use some random JSON Parser, you´ll get access_token and refresh_token
var Deserializer = new JavaScriptSerializer();
var Response = Deserializer.DeserializeObject(ApiResponse) as Dictionary<string, object>;
return new ImgurToken()
{
AccessToken = Convert.ToString(Response["access_token"]),
RefreshToken = Convert.ToString(Response["refresh_token"])
};
}
}
}
public class ImgurToken
{
public string AccessToken { get; set; }
public string RefreshToken { get; set; }
}

Related

Need to Access Google Drive V3 via IIS application - Without Using MVC

My need is very specific. I need to access a directory on Google Drive that is a shared folder. The only thing in it will be empty form documents and spreadsheet templates. There is nothing of value in the folder, and it is used internally only. So, I can be very optimistic WRT security concerns. I just need access.
I am extending an existing ERP system that runs as an IIS application.
My customization is .NET/C# project that extends the ERP's .NET classes. I cannot implement a login/auth system because one already exists for the ERP.
I did the .NET quickstart, but of course that is a console app, and will not work when I move it to IIS. The suggestion to follow the standard MVC model doesn't work for me -- adding a second web site/page is needlessly complicated for my needs.
My question is: How can I authorize access to a Google Drive that
A) Runs within IIS
B) Does not require a separate ASP Web Application to implement MVC for authorization.
=============================
Similar to issues in:
Google API Fails after hosting it to IIS
you could use OAuth authorization with your asp.net application:
Create Web Server client_secret.json.by using GetAuthorizationUrl() create url for get toke temporary token.Redirect to GoogleCallback() and get refresh and access tokens using ExchangeAuthorizationCode().Save them to the file "~/Resources/driveApiCredentials/drive-credentials.json/Google.Apis.Auth.OAuth2.Responses.TokenResponse-{account}".Use this saved tokens.
you could refer to the below link for more detail:
https://developers.google.com/api-client-library/dotnet/guide/aaa_oauth#web-applications-aspnet-mvc
Google Drive API upload Fails after hosting it to IIS. showing the error as Failed to launch the Browser with
Google Drive API not uploading file from IIS
Google Data API Authorization Redirect URI Mismatch
Jalpa's answer was not what I was looking for, nor was anything referenced in any of the links.
I'm going to put my answer here, because it is what I needed, and it might be useful to others.
First the overview
Google's QuickStart for .NET only shows the console based solution. As many have discovered, this does not work when you switch to an IIS based solution. It is almost as if the API deliberately defeats your attempts to do so. It simply will not allow you to use a token created for a local application using GoogleWebAuthorizationBroker.AuthorizeAsync -- it will error even if a browser isn't needed. (ie the token hasn't expired, so it won't need the browser to authenticate anything.)
Trying to run a refresh authorization gives you a token, but not a service. And even if the token is valid, you still can't use AuthorizeAsync to get your service from an IIS application (see above)
This is how I handle this:
Do the quick start and run the authorization that pops up the local browser and allows you to login and authenticate.
It creates a local folder(token.json), where it puts a token file (Google.Apis.Auth.OAuth2.Responses.TokenResponse-user) It's just a json file. Open it in notepad++ and you will find the fields:
"access_token": "token_type": "expires_in": "refresh_token":
"scope": "Issued": "IssuedUtc":
You need the refresh_token. I simply combined that with the initial credentials file I downloaded from the Google API Console (i.e. "credentials.json") and named it "skeleton_key.json"
This file is all you will need to generate valid tokens forever.
I have 2 classes I use for this. First the class that creates the Drive Service:
public class GDriveClass
{
public String LastErrorMessage { get; set; }
static string[] Scopes = { DriveService.Scope.Drive }; // could pull this from skeleton_key
static string ApplicationName = "GDrive Access"; // this is functionally irrelevant
internal UserCredential usrCredentials;
internal Google.Apis.Drive.v3.DriveService CurrentGDriveService = null;
internal String basePath = "."; // this comes in from calling program
// which uses HttpContext.Current.Server.MapPath("~");
public GDriveClass(string logFileBasePath)
{
basePath = logFileBasePath;
LastErrorMessage = "";
}
#region Google Drive Authenticate Code
public bool AuthenticateUser(string FullTokenAccessFileName)
{
UserCredential credential;
String JsonCredentialsonFile = System.IO.File.ReadAllText(FullTokenAccessFileName);
string credPath = basePath + #"\Credentials\token.json";
// Force a Refresh of the Token
RefreshTokenClass RTC = new RefreshTokenClass();
// Set field values in RefreshTokenClass:
var jObject = Newtonsoft.Json.Linq.JObject.Parse(JsonCredentialsonFile);
var fieldStrings = jObject.GetValue("installed").ToString();
var fields = Newtonsoft.Json.Linq.JObject.Parse(fieldStrings);
RTC.client_id = fields.GetValue("client_id").ToString();
RTC.client_secret = fields.GetValue("client_secret").ToString();
RTC.refresh_token = fields.GetValue("refresh_token").ToString();
RTC.ExecuteRefresh(); // this gets us a valid token every time
try
{
GoogleCredential gCredentials = GoogleCredential.FromAccessToken(RTC.access_token);
CurrentGDriveService = new DriveService(new BaseClientService.Initializer()
{
HttpClientInitializer = gCredentials,
ApplicationName = ApplicationName,
});
return true;
}
catch (Exception ex)
{
LastErrorMessage = "Error: Authenticating - " + ex.Message;
return false;
}
}
Usage is pretty straight forward:
string TokenFile = #basePath + #"\skeleton_key.json";
GDRIVER.AuthenticateUser(TokenFile);
var rslt = GDRIVER.LastErrorMessage;
if (!String.IsNullOrEmpty(rslt))
{
WriteToLogFile("ERROR in Google AuthenticateUser() ");
AlertMessage("Unable To Connect to Google Drive - Authorization Failed");
return;
}
And this is the class that refreshes the token via REST API as needed:
public class RefreshTokenClass
{
public string application_name { get; set; }
public string token_source { get; set; }
public string client_id { get; set; }
public string client_secret { get; set; }
public string scope { get; set; }
public string access_token { get; set; }
public string refresh_token { get; set; }
public RefreshTokenClass()
{
}
public bool ExecuteRefresh()
{
try
{
RestClient restClient = new RestClient();
RestRequest request = new RestRequest();
request.AddQueryParameter("client_id", this.client_id);
request.AddQueryParameter("client_secret", this.client_secret);
request.AddQueryParameter("grant_type", "refresh_token");
request.AddQueryParameter("refresh_token", this.refresh_token);
restClient.BaseUrl = new System.Uri("https://oauth2.googleapis.com/token");
var restResponse = restClient.Post(request);
// Extracting output data from received response
string response = restResponse.Content.ToLower(); // make sure case isn't an issue
// Parsing JSON content into element-node JObject
var jObject = Newtonsoft.Json.Linq.JObject.Parse(restResponse.Content);
//Extracting Node element using Getvalue method
string _access_token = jObject.GetValue("access_token").ToString();
this.access_token = _access_token;
return true;
}
catch (Exception ex)
{
//Console.WriteLine("Error on Token Refresh" + ex.Message);
return false;
}
}
Note: This makes use of Newtonsoft.Json and RestSharp.
Thanks to user: "OL." who gave me the way of creating a service from a token (that somehow I missed in the docs!)
How to create Service from Access Token
And to user:"purshotam sah" for a clean REST API approach
Generate Access Token Using Refresh Token

How to correctly get access token in ShopifySharp .Net library?

I use https://github.com/nozzlegear/ShopifySharp .Net library to work with Shopify Api. I just create dev webshop and I want to test some GET methods. In documentation I saw next code:
string code = Request.QueryString["code"];
string myShopifyUrl = Request.QueryString["shop"];
string accessToken = await AuthorizationService.Authorize(code, myShopifyUrl, shopifyApiKey, shopifySecretKey);
All parameters I understand except first , what code is this , where I should get it?? Thanks
This is basically Authorization code
It is with respect to concept of "OAuth"
Refer:
https://help.shopify.com/api/getting-started/authentication/oauth
You should create a method in your controller which will receive a callback from Shopify:
public ActionResult Callback(string code, string shop) {
string accessToken = await AuthorizationService.Authorize(code, myShopifyUrl, shopifyApiKey, shopifySecretKey);
}
Then when you building authorization URL, you should set variable redirectUrl to the method above:
//This is the user's store URL.
string usersMyShopifyUrl = "https://example.myshopify.com";
// A URL to redirect the user to after they've confirmed app installation.
// This URL is required, and must be listed in your app's settings in your Shopify app dashboard.
// It's case-sensitive too!
string redirectUrl = "https://example.com/my/redirect/url";
//An array of the Shopify access scopes your application needs to run.
var scopes = new List<AuthorizationScope>()
{
AuthorizationScope.ReadCustomers,
AuthorizationScope.WriteCustomers
};
//Or, use an array of string permissions
var scopes = new List<string>()
{
"read_customers",
"write_customers"
}
//All AuthorizationService methods are static.
string authUrl = AuthorizationService.BuildAuthorizationUrl(scopes, usersMyShopifyUrl, shopifyApiKey, redirectUrl);
And once user will be redirected to authorization URL, it will open Shopify page where user will be able to install app. Then Shopify will redirect him to your callback method with code and shop parameters

Xamarin, Azure, customauth and passing parameters

I am in the process of rewritting our app using Xamarin.Forms with a C# backend and I'm trying to use customauth on login. I've got it working to a point but am struggling to pass back to the Xamarin app everything I want from the backend. I'm getting the token and user id but want a bit more.
The backend code on succesfull login seems relatively straightforward:
return Ok(GetLoginResult(body));
where GetLoginResult() is:
private object GetLoginResult(IUser body)
{
var claims = new Claim[]
{
new Claim(JwtRegisteredClaimNames.Sub, body.username)
};
JwtSecurityToken token = AppServiceLoginHandler.CreateToken(
claims, signingKey, audience, issuer, TimeSpan.FromDays(30));
accounts account = db.accounts.Single(u => u.username.Equals(body.username));
return new LoginResult(account)
{
authenticationToken = token.RawData,
};
}
and the LoginResult class is
public class LoginResult
{
public LoginResult(accounts account)
{
Response = 200;
CustomerId = account.CustomerId;
Modules = account.Modules;
User = new LoginResultUser
{
userId = account.id,
UserName = account.UserName,
EmployeeId = account.EmployeeId
};
}
[JsonProperty(PropertyName = "Response")]
public int Response { get; set; }
etc
In the app, I'm calling the customauth as follows:
MobileServiceUser azureUser = await _client.LoginAsync("custom", JObject.FromObject(account));
The result has the token and the correct userid but how can I fill the result with the additional properties passed back by the backend? I've got the backend working and tested using postman and the results I get there are what I want but I've been unable to find out how to get it deserialized in the app.
As I known, for custom auth , MobileServiceClient.LoginAsync would invoke https://{your-app-name}.azurewebsites.net/.auth/login/custom. When using ILSPy you could find that this method would only retrieve the user.userId and authenticationToken from the response to construct the CurrentUser of your MobileServiceClient. Per my understanding, you could leverage MobileServiceClient.InvokeApiAsync to retrieve the additional user info after the user has logged in successfully. Additionally, you could try to follow this toturial for other possible approaches.
UPDATE
You could use InvokeApiAsync instead of LoginAsync to invoke the custom login endpoint directly, then retrieve the response and get the additional parameters as follows:
When logged successfully, I added a new property userName and response the client as follows:
For the client, I added a custom extension method for logging and retrieve the additional parameters as follows:
Here are the code snippet, you could refer to them:
MobileServiceLoginExtend.cs
public static class MobileServiceLoginExtend
{
public static async Task CustomLoginAsync(this MobileServiceClient client, LoginAccount account)
{
var jsonResponse = await client.InvokeApiAsync("/.auth/login/custom", JObject.FromObject(account), HttpMethod.Post, null);
//after successfully logined, construct the MobileServiceUser object with MobileServiceAuthenticationToken
client.CurrentUser = new MobileServiceUser(jsonResponse["user"]["userId"].ToString());
client.CurrentUser.MobileServiceAuthenticationToken = jsonResponse.Value<string>("authenticationToken");
//retrieve custom response parameters
string customUserName = jsonResponse["user"]["userName"].ToString();
}
}
Login processing
MobileServiceClient client = new MobileServiceClient("https://bruce-chen-002-staging.azurewebsites.net/");
var loginAccount = new LoginAccount()
{
username = "brucechen",
password = "123456"
};
await client.CustomLoginAsync(loginAccount);

Twitch API Call from C# streams/followed

I had developed my own C# application to make calls to twitch api to get list of all the live users i am currently following. It was working fine until April or something.
I pass this string to the call in the code via WebClient.DownloadString to be parsed with json:
https://api.twitch.tv/kraken/streams/followed?oauth_token=[mytoken]&stream_type=live
This used to work fine and returned a long parsable string from web which i used in my app.
But now the string returned says that i am missing the scope.(my oauth is correct)
So i went on and tried this on a web browser to check if my oauth is correct via this link: https://api.twitch.tv/kraken?oauth_token=[my oauth]
This returns a valid string but;
It turns out that the token i got from web has only chat_login scope. I want to set a user_read scope or at least retrieve a token which has user_read scope. Not chat_login scope; as chat_login scope does not permit me getting string via https//api.twitch.tv/kraken/streams/followed?oauth_token=[mytoken]&stream_type=live
In the authentication manual of twitch api in github there is a process which requires a call that grants my application access to my twitch info. I need to specify redirect_uri there to get the access_token which has the user_read scope.
But i have no idea about how to specify a redirect_uri and which function to call that will return the access_token string with the user_read scope that i need.
Is this new in v3 twitch api? (Which is probably changed around in April?)
To summarize: What should i do to get an #access_token which has a user_read scope rather than chat_login scope?
My Code:
public partial class Form1 : Form
{
const string chName = "ryetta";
const string FollowsURL = "https://api.twitch.tv/kraken/users/" + chName + "/follows/channels?limit=200&sortby=last_broadcast";
const string oauth = "4yk...";
const string FollowedURL = "https://api.twitch.tv/kraken/streams/followed?oauth_token=" + oauth + "&stream_type=live";
BindingList<ChannelData> channels = new BindingList<ChannelData>();
WebClient wc;
string selectedChannelName;
public Form1()
{
InitializeComponent();
wc = new WebClient();
}
private void button1_Click(object sender, EventArgs e)
{
string s = jsonget(FollowedURL); // this is where i get the scope error so the other parts of the code is irrelevant
//JObject jObj = JObject.Parse(s);
StreamFollowed streams1 = JsonConvert.DeserializeObject<StreamFollowed>(s);
channels.Clear();
foreach (Stream stream in streams1.streams)
{
System.IO.Stream str = wc.OpenRead(stream.preview.medium);
Bitmap bmp = new Bitmap(str);
channels.Add(new ChannelData(stream, bmp));
}
dataGridView1.DataSource = channels.Select(cdata => new {
cdata.Name,
cdata.ViewerCount,
cdata.Game,
cdata.Title,
cdata.UpTimeString,
cdata.BmpPreview,
cdata.followersCount,
cdata.ratio}).ToList();
selectedChannelName = (string)dataGridView1.SelectedRows[0].Cells[0].Value;
}
public string jsonget(string url)
{
return wc.DownloadString(url);
}
Thanks in advance for your time.
I'm not sure if this is correct or not but the URL you use for the api call I think has changed
https//api.twitch.tv/kraken/streams/followed?oauth_token=[mytoken]&stream_type=live
https//api.twitch.tv/kraken/channels/followed?oauth_token=[mytoken]&stream_type=live
I think they changed it from streams to channels
Sorry if this doesn't help though

Bing Ads OAuth Automation using only .NET?

How can I log onto Microsoft Live (with .NET WebClient?) and automate the OAuth process to get a token to make Bing Ads API calls?
My question is similar to How do I get an OAuth request_token from live.com?. However, I am building (C#, .NET 4.5.2) a headless Windows Service using the context of a Bing Ads super admin account that is linked to multiple other Bing Ads accounts. The idea is to authenticate, get the auth bits, and then make calls using the bits at 3:00am. Some of the accounts "compete" so for example group A should not see data from group B, so having an application get data for everyone and filter it and distribute it overnight solves many business problems.
I am concerned that if Live experiences problems, or our application is down for an extended time for any reason, we will have to re-authenticate manually to get data again. Maintenance and management of the credentials is now additional overhead (this is for an enterprise environment) that will have to take the form of an intranet web site/page to allow junior/uninitiated folks to do the work if needed (lets not forget testing and documentation). To contrast, Google provides an option to use key pairs for groups that need to work in a fully automated manner. It appears that Twitter's OAuth2 implementation can be automated without a GUI logon. It appears that other Bing services (eg Translation) can also be automated with WebClient.
I have the Microsoft account name and password already, and have a callback URL of "local-mydomain.com" set in the Bing Ads app GUI (and have a HOSTS entry for local-mydomain.com).
The Microsoft sample appears to work, but it automates the MS Web Browser Control, expects a user to input credentials in the GUI, and then the token is given. Giving the super admin account to users to do this is not an option. Expecting a user to get up at 3:00am to authenticate to upload/download data is not an option. Expecting a user to get desktop access to a server in the farm to "run something" is not an option.
All OAuth ideas appreciated.
Thanks.
Here is the launching code:
partial class OAuthForm : Form
{
private static OAuthForm _form;
private static WebBrowser _browser;
private static string _code;
private static string _error;
// When you register your application, the Client ID is provisioned.
private const string ClientId = "000redacted000";
// Request-related URIs that you use to get an authorization code,
// access token, and refresh token.
private const string AuthorizeUri = "https://login.live.com/oauth20_authorize.srf";
private const string TokenUri = "https://login.live.com/oauth20_token.srf";
private const string DesktopUri = "https://login.live.com/oauth20_desktop.srf";
private const string RedirectPath = "/oauth20_desktop.srf";
private const string ConsentUriFormatter = "{0}?client_id={1}&scope=bingads.manage&response_type=code&redirect_uri={2}";
private const string AccessUriFormatter = "{0}?client_id={1}&code={2}&grant_type=authorization_code&redirect_uri={3}";
private const string RefreshUriFormatter = "{0}?client_id={1}&grant_type=refresh_token&redirect_uri={2}&refresh_token={3}";
// Constructor
public OAuthForm(string uri)
{
InitializeForm(uri);
}
[STAThread]
static void Main()
{
// Create the URI to get user consent. Returns the authorization
// code that is used to get an access token and refresh token.
var uri = string.Format(ConsentUriFormatter, AuthorizeUri, ClientId, DesktopUri);
_form = new OAuthForm(uri);
// The value for "uri" is
// https://login.live.com/oauth20_authorize.srf?client_id=000redacted000&scope=bingads.manage&response_type=code&redirect_uri=https://login.live.com/oauth20_desktop.srf
_form.FormClosing += form_FormClosing;
_form.Size = new Size(420, 580);
Application.EnableVisualStyles();
// Launch the form and make an initial request for user consent.
// For example POST /oauth20_authorize.srf?
// client_id=<ClientId>
// &scope=bingads.manage
// &response_type=code
// &redirect_uri=https://login.live.com/oauth20_desktop.srf HTTP/1.1
Application.Run(_form); // <!---------- Problem is here.
// I do not want a web browser window to show,
// I need to automate the part of the process where
// a user enters their name/password and are
// redirected.
// While the application is running, browser_Navigated filters traffic to identify
// the redirect URI. The redirect's query string will contain either the authorization
// code if the user consented or an error if the user declined.
// For example https://login.live.com/oauth20_desktop.srf?code=<code>
// If the user did not give consent or the application was
// not registered, the authorization code will be null.
if (string.IsNullOrEmpty(_code))
{
Console.WriteLine(_error);
return;
}
Whatever you do, the "super admin" will have to log on at least once, using a browser. You can do that by hosting a simple web page in your service, or you could do it as part of the setup process. The Live samples show you how to do that.
Once the "super admin" has logged on using the code grant, you receive an access token and a refresh token. I'm not sure how long the Live access token is valid, but it is probably log enough for one nightly run. Save the refresh token in a safe place. The following night, you start by exchanging that refresh token by a new access token and a new refresh token. Again, you save this new refresh token for the following night.
You can keep this process running forever, as long as the "super admin" does not revoke the authorization he gave to your app.
UPDATE:
Some OAuth 2.0 servers support the "Resource Owner Password Credentials Grant", see the RFC at https://www.rfc-editor.org/rfc/rfc6749. If the Live server supports that, it would be an alternative to the Code Grant that does not require a browser. However, even of the server supports it, I would recommend against it for security reasons, as it requires storing your "super admin" password on the server. If someone grabs the password, they have full access to the account, and all resources protected by it. It will also break down if you change the password. The code grant does not have these problems.
Your question states that you want or need to run as this "super admin". An other option might be to use the "Client Credentials Grant". However, this also requires a client secret to be stored on the server (as with the password credentials grant). Furthermore, it still requires the super admin to authorize the client, and that in itself requires a code grant using a browser.
You ask why the code grant requires a browser, why you can not use some kind of screen scraping to simulate a browser interaction. First of all, you cannot predict the screens that will be shown to the user. These screens change without notice. More importantly, depending on user options and history, the server shows different screens. For example, the user may have turned on two-factor authentication. Last but not least, why do you object to opening a browser? It will probably be easier than trying to emulate it.
Finally, these "super admin" users might object to giving their password to your application, as they don't really know what you are doing with it (you might be sending to a server of your own, as far as they know). Using the Code Grant with a browser, they know your application never gets to see their password (kind of - you could listen in on browser events or something, unless the browser control is run in a separate process not under your control, such as the Windows 8 WebAuthenticationBroker). Your application only gets a token with the scopes they authorize.
After spending a few hours on this problem for myself and finding absolutely no solution to automate connecting to Bing from a service. Here is what will work using the wonderful WatiN
First grab WatiN and add it to your solution via Nuget.
Then use the following code (my example works in a console application as an Example) to automate the whole grabbing of a token from Microsoft. It's not perfect as this is a sample but it will work.
You should double check the element ID's I'm using in case they changed, they are hard coded - generally remove all the hard coding if your going to use this in a production environment.
I didn't want anyone else to have to go through this.
First it grabs a Code that is then used to grab a Token, just like the OAuth 2.0 specification requires.
using System;
using System.Collections.Generic;
using System.Net;
using System.IO;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Json;
using System.Text;
using WatiN.Core.Native;
using WatiN.Core;
namespace LouiesOAuthCodeGrantFlow
{
// Using access tokens requires that you register your application and that
// the user gives consent to your application to access their data. This
// example uses a form and WebBrowser control to get the user's consent.
// The control and form require a single-threaded apartment.
partial class LouiesBingOAuthAutomation
{
private static LouiesBingOAuthAutomation _form;
private static string _code;
private static string _error;
//your going to want to put these in a secure place this is for the sample
public const string UserName = "your microsoft user name";
public const string Password = "<your microsoft account password";
// When you register your application, the Client ID is provisioned.
//get your clientid https://developers.bingads.microsoft.com/Account
private const string ClientId = "<your client id>";
// Request-related URIs that you use to get an authorization code,
// access token, and refresh token.
private const string AuthorizeUri = "https://login.live.com/oauth20_authorize.srf";
private const string TokenUri = "https://login.live.com/oauth20_token.srf";
private const string DesktopUri = "https://login.live.com/oauth20_desktop.srf";
private const string RedirectPath = "/oauth20_desktop.srf";
private const string ConsentUriFormatter = "{0}?client_id={1}&scope=bingads.manage&response_type=code&redirect_uri={2}";//&displayNone
private const string AccessUriFormatter = "{0}?client_id={1}&code={2}&grant_type=authorization_code&redirect_uri={3}";
private const string RefreshUriFormatter = "{0}?client_id={1}&grant_type=refresh_token&redirect_uri={2}&refresh_token={3}";
// Constructor
public LouiesBingOAuthAutomation(string uri)
{
InitializeForm(uri);
}
[STAThread]
static void Main()
{
var uri = string.Format(ConsentUriFormatter, AuthorizeUri, ClientId, DesktopUri);
_form = new LouiesBingOAuthAutomation(uri);
if (string.IsNullOrEmpty(_code))
{
Console.WriteLine(_error);
return;
}
uri = string.Format(AccessUriFormatter, TokenUri, ClientId, _code, DesktopUri);
AccessTokens tokens = GetAccessTokens(uri);
Console.WriteLine("Access token expires in {0} minutes: ", tokens.ExpiresIn / 60);
Console.WriteLine("\nAccess token: " + tokens.AccessToken);
Console.WriteLine("\nRefresh token: " + tokens.RefreshToken);
uri = string.Format(RefreshUriFormatter, TokenUri, ClientId, DesktopUri, tokens.RefreshToken);
tokens = GetAccessTokens(uri);
Console.WriteLine("Access token expires in {0} minutes: ", tokens.ExpiresIn / 60);
Console.WriteLine("\nAccess token: " + tokens.AccessToken);
Console.WriteLine("\nRefresh token: " + tokens.RefreshToken);
}
private void InitializeForm(string uri)
{
using (var browser = new IE(uri))
{
var page = browser.Page<MyPage>();
page.PasswordField.TypeText(Password);
try
{
StringBuilder js = new StringBuilder();
js.Append(#"var myTextField = document.getElementById('i0116');");
js.Append(#"myTextField.setAttribute('value', '"+ UserName + "');");
browser.RunScript(js.ToString());
var field = browser.ElementOfType<TextFieldExtended>("i0116");
field.TypeText(UserName);
}
catch (Exception ex)
{
Console.Write(ex.Message + ex.StackTrace);
}
page.LoginButton.Click();
browser.WaitForComplete();
browser.Button(Find.ById("idBtn_Accept")).Click();
var len = browser.Url.Length - 43;
string query = browser.Url.Substring(43, len);
if (query.Length == 50)
{
if (!string.IsNullOrEmpty(query))
{
Dictionary<string, string> parameters = ParseQueryString(query, new[] { '&', '?' });
if (parameters.ContainsKey("code"))
{
_code = parameters["code"];
}
else
{
_error = Uri.UnescapeDataString(parameters["error_description"]);
}
}
}
}
}
// Parses the URI query string. The query string contains a list of name-value pairs
// following the '?'. Each name-value pair is separated by an '&'.
private static Dictionary<string, string> ParseQueryString(string query, char[] delimiters)
{
var parameters = new Dictionary<string, string>();
string[] pairs = query.Split(delimiters, StringSplitOptions.RemoveEmptyEntries);
foreach (string pair in pairs)
{
string[] nameValue = pair.Split(new[] { '=' });
parameters.Add(nameValue[0], nameValue[1]);
}
return parameters;
}
// Gets an access token. Returns the access token, access token
// expiration, and refresh token.
private static AccessTokens GetAccessTokens(string uri)
{
var responseSerializer = new DataContractJsonSerializer(typeof(AccessTokens));
AccessTokens tokenResponse = null;
try
{
var realUri = new Uri(uri, UriKind.Absolute);
var addy = realUri.AbsoluteUri.Substring(0, realUri.AbsoluteUri.Length - realUri.Query.Length);
var request = (HttpWebRequest)WebRequest.Create(addy);
request.Method = "POST";
request.ContentType = "application/x-www-form-urlencoded";
using (var writer = new StreamWriter(request.GetRequestStream()))
{
writer.Write(realUri.Query.Substring(1));
}
var response = (HttpWebResponse)request.GetResponse();
using (Stream responseStream = response.GetResponseStream())
{
if (responseStream != null)
tokenResponse = (AccessTokens)responseSerializer.ReadObject(responseStream);
}
}
catch (WebException e)
{
var response = (HttpWebResponse)e.Response;
Console.WriteLine("HTTP status code: " + response.StatusCode);
}
return tokenResponse;
}
}
public class MyPage : WatiN.Core.Page
{
public TextField PasswordField
{
get { return Document.TextField(Find.ByName("passwd")); }
}
public WatiN.Core.Button LoginButton
{
get { return Document.Button(Find.ById("idSIButton9")); }
}
}
[ElementTag("input", InputType = "text", Index = 0)]
[ElementTag("input", InputType = "password", Index = 1)]
[ElementTag("input", InputType = "textarea", Index = 2)]
[ElementTag("input", InputType = "hidden", Index = 3)]
[ElementTag("textarea", Index = 4)]
[ElementTag("input", InputType = "email", Index = 5)]
[ElementTag("input", InputType = "url", Index = 6)]
[ElementTag("input", InputType = "number", Index = 7)]
[ElementTag("input", InputType = "range", Index = 8)]
[ElementTag("input", InputType = "search", Index = 9)]
[ElementTag("input", InputType = "color", Index = 10)]
public class TextFieldExtended : TextField
{
public TextFieldExtended(DomContainer domContainer, INativeElement element)
: base(domContainer, element)
{
}
public TextFieldExtended(DomContainer domContainer, ElementFinder finder)
: base(domContainer, finder)
{
}
public static void Register()
{
Type typeToRegister = typeof(TextFieldExtended);
ElementFactory.RegisterElementType(typeToRegister);
}
}
// The grant flow returns more fields than captured in this sample.
// Additional fields are not relevant for calling Bing Ads APIs or refreshing the token.
[DataContract]
class AccessTokens
{
[DataMember]
// Indicates the duration in seconds until the access token will expire.
internal int expires_in = 0;
[DataMember]
// When calling Bing Ads service operations, the access token is used as
// the AuthenticationToken header element.
internal string access_token = null;
[DataMember]
// May be used to get a new access token with a fresh expiration duration.
internal string refresh_token = null;
public string AccessToken { get { return access_token; } }
public int ExpiresIn { get { return expires_in; } }
public string RefreshToken { get { return refresh_token; } }
}
}

Categories

Resources