Hi guys im trying to use dropnet as means to be using dropbox as a cloud storage for my application, and following the 3 step process using the normal 0auth
1.Get Request Token[done]
2.Send user for authorization, and get back verifier[done]
3.Get Access token using the original Request Token and the verifier[issue!]
if i understand the api correctly since i want to use a single account for my storage i need api key,api secret,token and secret.the token and secret seems to be accessible from the third steps and its my trouble.
from the second step i get this url
https://www.dropbox.com/1/oauth/authorize?oauth_token=xxxxxxxxxx
before pressing authenticate to allow my app to use dropbox
from the documentation i read that you need to use this method
UserLogin GetAccessToken(string code, string redirectUri);
i am assuming here xxxxx is the string code
to validate that is the original
so i made code as follows
var accessToken = client.GetAccessToken("xxxxxxx","https://www.dropbox.com/1/oauth/authorize?oauth_token=xxxxxxxxxx);
var ats =accessToken.Secret;
var att = accessToken.Token;
Console.Writeline(ats);
Console.Writeline(att):
in hopes of getting the console to print my secret and token for my acct but it dosent work ?Giving me the error of
An unhandled exception of type 'DropNet.Exceptions.DropboxRestException' occurred in DropNet.dll
help please !
Solved the problem myself,here is the full code
DropNetClient client = new DropNetClient(variable.ApiKey, variable.ApiSecret);
]
var response =client.GetToken();
var t = response.Token;
var s = response.Secret;
Console.WriteLine(s);
Console.WriteLine(t);
var authorizeUrl = client.BuildAuthorizeUrl(new DropNet.Models.UserLogin
{
Secret = s,
Token = t
}
);
DropNetClient client2= new DropNetClient(variable.ApiKey, variable.ApiSecret,t,s);
// Prompt for user to auth
Process.Start(authorizeUrl);
// PRESS KEY AFTER authorization AFTER
Console.ReadKey();
// If the user authed, let's get that token
try
{
var Token = client2.GetAccessToken();
var userToken = Token.Token;
var userSecret = Token.Secret;
Console.WriteLine(userSecret);//ACCESS TOKEN SECRET
Console.WriteLine(userToken);//ACCESS TOKEN
Console.ReadKey();
}
catch (Exception e)
{
Console.WriteLine("Exception! " + e.Message);
Console.ReadKey();
}
// save for later
Related
I'm learning to build Windows 10 apps with an azure backend. I'm using Micosoft Account as my authentication provider. I've learned how to cache access tokens but I'm a little hung up on refresh tokens.
As I understand it, the access token is short lived, and the longer expiring refresh token allows me to get a new access token. I've been trying to follow along with Adrian Hall's book here: https://adrianhall.github.io/develop-mobile-apps-with-csharp-and-azure/chapter2/realworld/#refresh-tokens
My problem is that I don't quite understand when/where to call or how to use "client.RefreshUserAsync();" and the book isn't really clear.
When should I call refresh?? I guess the problem is that the token might expire in the middle of the user using the app, forcing the user to login again right? So do I call refresh every time my user does anything? I'm confused.
Right now, my app just has a single AuthenticateAsync method on my mainpage that executes when a user clicks a login button. It looks for a cached token, if there is one it checks expiration and re-authenticates if expired.
private async System.Threading.Tasks.Task<bool> AuthenticateAsync()
{
string message;
bool success = false;
var provider = MobileServiceAuthenticationProvider.MicrosoftAccount;
// Use the PasswordVault to securely store and access credentials
PasswordVault vault = new PasswordVault();
PasswordCredential credential = null;
try
{
//try to get an existing credential from the vault.
credential = vault.FindAllByResource(provider.ToString()).FirstOrDefault();
}
catch (Exception)
{
//When there is no matching resource an error occurs, which we ignore.
}
if (credential != null)
{
// Create a user from the stored credentials.
user = new MobileServiceUser(credential.UserName);
credential.RetrievePassword();
user.MobileServiceAuthenticationToken = credential.Password;
// Set the user from the stored credentials.
App.MobileService.CurrentUser = user;
success = true;
message = string.Format("Cached credentials for user - {0}", user.UserId);
// Consider adding a check to determine if the token is
// expired, as shown in this post: http://aka.ms/jww5vp
//check expiration
if (App.MobileService.IsTokenExpired())
{
//remove the expired credentials
vault.Remove(credential);
try
{
// Login with the identity provider
user = await App.MobileService.LoginAsync(MobileServiceAuthenticationProvider.MicrosoftAccount);
// Create and store the user credentials.
credential = new PasswordCredential(provider.ToString(),
user.UserId, user.MobileServiceAuthenticationToken);
vault.Add(credential);
message = string.Format("Expired credentials caused re-authentication. You are now signed in - {0}", user.UserId);
success = true;
}
catch (InvalidOperationException)
{
message = "You must log in. Login required.";
}
}
}
else
{
try
{
// Login with the identity provider
user = await App.MobileService.LoginAsync(MobileServiceAuthenticationProvider.MicrosoftAccount);
// Create and store the user credentials.
credential = new PasswordCredential(provider.ToString(),
user.UserId, user.MobileServiceAuthenticationToken);
vault.Add(credential);
message = string.Format("You are now signed in - {0}", user.UserId);
success = true;
}
catch (InvalidOperationException)
{
message = "You must log in. Login required.";
}
}
var dialog = new MessageDialog(message);
dialog.Commands.Add(new UICommand("OK"));
await dialog.ShowAsync();
return success;
}
I guess the problem is that the token might expire in the middle of the user using the app, forcing the user to login again right?
Based on your description, you use Azure mobile app as your UWP backend. To access mobile app we need to use access token. and as you know that, access token will be expired. In order to get a new access token, we need to use refresh token. For how to get access token by refresh token, please refer to this article. Below is detailed http request info:
// Line breaks for legibility only
POST /{tenant}/oauth2/token HTTP/1.1
Host: https://login.microsoftonline.com
Content-Type: application/x-www-form-urlencoded
client_id=6731de76-14a6-49ae-97bc-6eba6914391e
&refresh_token=OAAABAAAAiL9Kn2Z27UubvWFPbm0gLWQJVzCTE9UkP3pSx1aXxUjq...
&grant_type=refresh_token
&resource=https%3A%2F%2Fservice.contoso.com%2F
&client_secret=JqQX2PNo9bpM0uEihUPzyrh // NOTE: Only required for web apps
From above http request, we only provide client_id, refresh_token, grant_type, resource, client_secret(web app only). So we need not to let user login again.
When should I call refresh??
If the access token is expired, it will get error when we access mobile app. At this moment we can try to get a new access token by refresh token in the catch{} logic.
I'm suddenly starting to get the following exception when attempting to authenticate and access a spreadsheet on Google drive:
Unhandled Exception: Google.GData.Client.GDataRequestException:
Execution of aut hentication request returned unexpected
result: 404
at Google.GData.Client.Utilities.getAuthException(TokenCollection tokens,
Htt pWebResponse response)
at Google.GData.Client.Utilities.QueryClientLoginToken(GDataCredentials
gc, S tring serviceName, String applicationName, Boolean
fUseKeepAlive, IWebProxy prox yServer, Uri
clientLoginHandler)
at Google.GData.Client.GDataGAuthRequest.QueryAuthToken(GDataCredentials
gc)
at Google.GData.Client.GDataGAuthRequest.EnsureCredentials()
at Google.GData.Client.GDataRequest.EnsureWebRequest()
at Google.GData.Client.GDataGAuthRequest.EnsureWebRequest()
at Google.GData.Client.GDataRequest.Execute()
at Google.GData.Client.GDataGAuthRequest.Execute(Int32 retryCounter)
at Google.GData.Client.GDataGAuthRequest.Execute()
at Google.GData.Client.Service.Query(Uri queryUri, DateTime ifModifiedSince, String etag, Int64& contentLength)
at Google.GData.Client.Service.Query(FeedQuery feedQuery)
at Google.GData.Documents.DocumentsService.Query(DocumentsListQuery
feedQuery )
at GoogleLogger.GoogleService.getLastXECLogRows(String folderName, String fileName, Int32 rows)
This is in code that has been running for two years without any problems. I first thought that I may have lost access permissions on my production system but Google drive loads fine in my web browser. Tried it on several other systems and am getting the very same.
Did they change something in the Google API today? This can't be coincidence!
Google has retired their older authentication API. OAuth 2.0 should be used instead.
I spent too much time to figure out how to use newer Auth API with older GData API grabbing bits and pieces of information here and there from the Internet.
I decided to share all the the details with screenshots to save your time.
Go to https://console.developers.google.com/project
Hit Create Project button
Create project. Type in some name.
Go to API & Auth > Credentials and hit Create new Client ID button. It will create JSON key for you automatically - ignore that.
Hit Generate new P12 key
File download will start automatically. Remember the password, you will need it to open the file you just downloaded.
Rename downloaded file to Key.p12 and add it to your solution. Make sure you set Build Action and Copy to Output Directory accordingly.
Install Google API Auth using Nuget. Type the following in the Package Manager Console
Install-Package Google.Apis.Auth
Copy service account email address that was generated in Step #4.
Grant appropriate permission to this user in your Google Spreadsheet.
Use the following code to query the spreadsheet. Replace email and Google spreadsheet URL address in the code below.
const string ServiceAccountEmail = "452351479-q41ce1720qd9l94s8847mhc0toao1fed#developer.gserviceaccount.com";
var certificate = new X509Certificate2("Key.p12", "notasecret", X509KeyStorageFlags.Exportable);
var serviceAccountCredentialInitializer =
new ServiceAccountCredential.Initializer(ServiceAccountEmail)
{
Scopes = new[] { "https://spreadsheets.google.com/feeds" }
}.FromCertificate(certificate);
var credential = new ServiceAccountCredential(serviceAccountCredentialInitializer);
if (!credential.RequestAccessTokenAsync(System.Threading.CancellationToken.None).Result)
throw new InvalidOperationException("Access token request failed.");
var requestFactory = new GDataRequestFactory(null);
requestFactory.CustomHeaders.Add("Authorization: Bearer " + credential.Token.AccessToken);
var service = new SpreadsheetsService(null) { RequestFactory = requestFactory };
var query = new ListQuery("https://spreadsheets.google.com/feeds/list/0ApZkobM61WIrdGRYshh345523VNsLWc/1/private/full");
var feed = service.Query(query);
var rows = feed.Entries
.Cast<ListEntry>()
.Select(arg =>
new
{
Field0 = arg.Elements[0].Value,
Field1 = arg.Elements[1].Value
})
.ToList();
I've managed to solve this by using this solution with Service Account with oAuth2.0
Accessing older GData APIs (Spreadsheet API) using OAuth 2 and a service account
The solution:
1. Create Project and Google Service Account in https://console.developers.google.com/project
Generate your p12 key.
Allow APIs in Developer console you want to use (basically we are going to use old API, so you can skip this step, but just in case)
Use the code below (.NET Framework 4.5!)
Also don't forget to grant "youraccount#developer.gserviceaccount.com" access to your spreadsheet document as you grant permissions for usual users by pressing Share.
Code:
using System.Security.Cryptography.X509Certificates;
using Google.GData.Client;
using Google.GData.Extensions;
using Google.GData.Spreadsheets;
using Google.Apis.Auth.OAuth2;
string keyFilePath = #"C:\key.p12"; // found in developer console
string serviceAccountEmail = "youraccount#developer.gserviceaccount.com"; // found in developer console
var certificate = new X509Certificate2(keyFilePath, "notasecret", X509KeyStorageFlags.Exportable);
ServiceAccountCredential credential = new ServiceAccountCredential(new ServiceAccountCredential.Initializer(serviceAccountEmail) //create credential using certificate
{
Scopes = new[] { "https://spreadsheets.google.com/feeds/" } //this scopr is for spreadsheets, check google scope FAQ for others
}.FromCertificate(certificate));
credential.RequestAccessTokenAsync(System.Threading.CancellationToken.None).Wait(); //request token
var requestFactory = new GDataRequestFactory("Some Name");
requestFactory.CustomHeaders.Add(string.Format("Authorization: Bearer {0}", credential.Token.AccessToken));
SpreadsheetsService myService = new SpreadsheetsService("You App Name"); //create your old service
myService.RequestFactory = requestFactory; //add new request factory to your old service
SpreadsheetQuery query = new SpreadsheetQuery(); //do the job as you done it before
SpreadsheetFeed feed = myService.Query(query);
Alright, I figured it out. Step by step instructions as follows - also see the code I provided below. FYI, this runs in .Net 3.5 and unlike the solution offered previously there are no new dependencies. You should be up and running in no time.
If you haven't yet create your OAuth 2.0 credentials - I assume you already know how to get those but here:
a) Log into your Google developer console: http://console.developers.google.com
b) Create a project
c) Create your credentials - use 'installed application'
d) add the APIs that you need - I think Drive API is definitely required. I also added Drive SDK just in case.
Copy the code below into VS and edit the first Main() method with your client key and secret key.
Run the app and copy both the new access token and the refresh token. Put those and your remaining credentials into the second Main() method below.
You now should be able to run the second Main() method (just reverse the naming). From now on that will be all you need - there is no need to re-run the first Main() method.
BTW, the first Main() method below was found here: https://developers.google.com/google-apps/spreadsheets/authorize
I did however add the missing token type as well the access type. Those are needed, so use the code below:
using System;
using Google.GData.Client;
using Google.GData.Spreadsheets;
using Google.GData.Documents;
using System.Configuration;
using System.Collections.Specialized;
namespace GoogleSpreadsheet
{
class GoogleOAutho2
{
private static String folderName = "crazy.ivan";
static void Main(string[] args)
{
////////////////////////////////////////////////////////////////////////////
// STEP 1: Configure how to perform OAuth 2.0
////////////////////////////////////////////////////////////////////////////
// TODO: Update the following information with that obtained from
// https://code.google.com/apis/console. After registering
// your application, these will be provided for you.
string CLIENT_ID = "your_client_id";
// This is the OAuth 2.0 Client Secret retrieved
// above. Be sure to store this value securely. Leaking this
// value would enable others to act on behalf of your application!
string CLIENT_SECRET = "your_secret_key"
// Space separated list of scopes for which to request access.
string SCOPE = "https://www.googleapis.com/auth/drive https://spreadsheets.google.com/feeds https://docs.google.com/feeds";
// This is the Redirect URI for installed applications.
// If you are building a web application, you have to set your
// Redirect URI at https://code.google.com/apis/console.
string REDIRECT_URI = "urn:ietf:wg:oauth:2.0:oob";
string TOKEN_TYPE = "refresh";
////////////////////////////////////////////////////////////////////////////
// STEP 2: Set up the OAuth 2.0 object
////////////////////////////////////////////////////////////////////////////
// OAuth2Parameters holds all the parameters related to OAuth 2.0.
OAuth2Parameters parameters = new OAuth2Parameters();
// Set your OAuth 2.0 Client Id (which you can register at
// https://code.google.com/apis/console).
parameters.ClientId = CLIENT_ID;
// Set your OAuth 2.0 Client Secret, which can be obtained at
// https://code.google.com/apis/console.
parameters.ClientSecret = CLIENT_SECRET;
// Set your Redirect URI, which can be registered at
// https://code.google.com/apis/console.
parameters.RedirectUri = REDIRECT_URI;
////////////////////////////////////////////////////////////////////////////
// STEP 3: Get the Authorization URL
////////////////////////////////////////////////////////////////////////////
// Set the scope for this particular service.
parameters.Scope = SCOPE;
parameters.AccessType = "offline"; // IMPORTANT and was missing in the original
parameters.TokenType = TOKEN_TYPE; // IMPORTANT and was missing in the original
// Get the authorization url. The user of your application must visit
// this url in order to authorize with Google. If you are building a
// browser-based application, you can redirect the user to the authorization
// url.
string authorizationUrl = OAuthUtil.CreateOAuth2AuthorizationUrl(parameters);
Console.WriteLine(authorizationUrl);
Console.WriteLine("Please visit the URL above to authorize your OAuth "
+ "request token. Once that is complete, type in your access code to "
+ "continue...");
parameters.AccessCode = Console.ReadLine();
////////////////////////////////////////////////////////////////////////////
// STEP 4: Get the Access Token
////////////////////////////////////////////////////////////////////////////
// Once the user authorizes with Google, the request token can be exchanged
// for a long-lived access token. If you are building a browser-based
// application, you should parse the incoming request token from the url and
// set it in OAuthParameters before calling GetAccessToken().
OAuthUtil.GetAccessToken(parameters);
string accessToken = parameters.AccessToken;
string refreshToken = parameters.RefreshToken;
Console.WriteLine("OAuth Access Token: " + accessToken + "\n");
Console.WriteLine("OAuth Refresh Token: " + refreshToken + "\n");
////////////////////////////////////////////////////////////////////////////
// STEP 5: Make an OAuth authorized request to Google
////////////////////////////////////////////////////////////////////////////
// Initialize the variables needed to make the request
GOAuth2RequestFactory requestFactory =
new GOAuth2RequestFactory(null, "MySpreadsheetIntegration-v1", parameters);
SpreadsheetsService service = new SpreadsheetsService("MySpreadsheetIntegration-v1");
service.RequestFactory = requestFactory;
// Make the request to Google
// See other portions of this guide for code to put here...
// Instantiate a SpreadsheetQuery object to retrieve spreadsheets.
Google.GData.Spreadsheets.SpreadsheetQuery query = new Google.GData.Spreadsheets.SpreadsheetQuery();
// Make a request to the API and get all spreadsheets.
SpreadsheetFeed feed = service.Query(query);
// Iterate through all of the spreadsheets returned
foreach (SpreadsheetEntry entry in feed.Entries)
{
// Print the title of this spreadsheet to the screen
Console.WriteLine(entry.Title.Text);
}
Console.ReadLine();
}
// once you copied your access and refresh tokens
// then you can run this method directly from now on...
static void MainX(string[] args)
{
GOAuth2RequestFactory requestFactory = RefreshAuthenticate();
SpreadsheetsService service = new SpreadsheetsService("MySpreadsheetIntegration-v1");
service.RequestFactory = requestFactory;
// Instantiate a SpreadsheetQuery object to retrieve spreadsheets.
Google.GData.Spreadsheets.SpreadsheetQuery query = new Google.GData.Spreadsheets.SpreadsheetQuery();
// Make a request to the API and get all spreadsheets.
SpreadsheetFeed feed = service.Query(query);
// Iterate through all of the spreadsheets returned
foreach (SpreadsheetEntry entry in feed.Entries)
{
// Print the title of this spreadsheet to the screen
Console.WriteLine(entry.Title.Text);
}
Console.ReadLine();
public static GOAuth2RequestFactory RefreshAuthenticate() {
OAuth2Parameters parameters = new OAuth2Parameters(){
RefreshToken = "the_refresh_token_you_copied_from_the_CLI_running_the_first_method";
AccessToken = "the_access_token_you_copied_from_the_CLI_running_the_first_method";
ClientId = "your_client_id";
ClientSecret = "your_dirty_little_secret";
Scope = "https://www.googleapis.com/auth/drive https://spreadsheets.google.com/feeds",
AccessType = "offline",
TokenType = "refresh"
};
string authUrl = OAuthUtil.CreateOAuth2AuthorizationUrl(parameters);
return new GOAuth2RequestFactory(null, "evilspeculator", parameters);
}
}
}
Hope that works for you guys - best of luck!
Andrew I was wondering how you got the google.apis.auth.oauth2 dll. Im trying to impliment your fix and I cant find the correct way to install the library.
I feel like I may be able to get this to work after I have that part.
I am attempting to download metric data from Google Analytics using C# and am performing user authentication with OAuth 2.0. I'm using the Installed Application authorisation flow, which requires logging into Google and copy-and-pasting a code into the application. I'm following the code taken from google-api-dotnet-client:
private void DownloadData()
{
Service = new AnalyticsService(new BaseClientService.Initializer() {
Authenticator = CreateAuthenticator(),
});
var request = service.Data.Ga.Get(AccountID, StartDate, EndDate, Metrics);
request.Dimensions = Dimensions;
request.StartIndex = 1;
request.MaxResults = 10000;
var response = request.Execute(); // throws Google.GoogleApiException
}
private IAuthenticator CreateAuthenticator()
{
var provider = new NativeApplicationClient(GoogleAuthenticationServer.Description) {
ClientIdentifier = "123456789012.apps.googleusercontent.com",
ClientSecret = "xxxxxxxxxxxxxxxxxxxxxxxx",
};
return new OAuth2Authenticator<NativeApplicationClient>(provider, Login);
}
private static IAuthorizationState Login(NativeApplicationClient arg)
{
// Generate the authorization URL.
IAuthorizationState state = new AuthorizationState(new[] { AnalyticsService.Scopes.AnalyticsReadonly.GetStringValue() });
state.Callback = new Uri(NativeApplicationClient.OutOfBandCallbackUrl);
Uri authUri = arg.RequestUserAuthorization(state);
// Request authorization from the user by opening a browser window.
Process.Start(authUri.ToString());
Console.Write("Google Authorization Code: ");
string authCode = Console.ReadLine();
// Retrieve the access token by using the authorization code.
state = arg.ProcessUserAuthorization(authCode, state);
return state;
}
The Google account xxxxxx#gmail.com registered the Client ID and secret. The same account has full administration rights in Google Analytics. When I try to pull data from Google Analytics, it goes through the authorisation process, which appears to work properly. Then it fails with:
Google.GoogleApiException
Google.Apis.Requests.RequestError
User does not have sufficient permissions for this profile. [403]
Errors [
Message[User does not have sufficient permissions for this profile.] Location[ - ] Reason [insufficientPermissions] Domain[global]
]
I've been struggling with this for a few hours. I've double checked that the correct user is being used, and is authorised on Google Analytics. I'm at a loss as to what is misconfigured. Any ideas as to what requires configuring or changing?
If auth seems to be working working then my suggestion is that you make sure you're providing the correct ID because based on your code snippet:
var request = service.Data.Ga.Get(AccountID, StartDate, EndDate, Metrics);
one can only assume that you're using the Account ID. If so, that is incorrect and you'd receive the error you've encountered. You need to query with the Profile ID.
If you login to Google Analytics using the web interface you'll see the following pattern in URL of the browser's address bar:
/a12345w654321p9876543/
The number following the p is the profile ID, so 9876543 in the example above. Make sure you're using that and actually you should be using the table id which would be ga:9876543.
If it isn't an ID issue then instead query the Management API to list accounts and see what you have access to and to verify auth is working correctly.
This can help : https://developers.google.com/analytics/devguides/reporting/core/v3/coreErrors, look error 403.
//Thanks for this post. The required profile id can be read from the account summaries.
Dictionary profiles = new Dictionary();
var accounts = service.Management.AccountSummaries.List().Execute();
foreach (var account in accounts.Items)
{
var profileId = account.WebProperties[0].Profiles[0].Id;
profiles.Add("ga:" + profileId, account.Name);
}
So I've looked at all the of the suggestions from the Linq to Twitter documentation regarding 401 statuses with Oauth and I honestly don't know what I'm doing wrong.
var auth = new PinAuthorizer
{
Credentials = new InMemoryCredentials
{
ConsumerKey = ConfigurationManager.AppSettings["twitterConsumerKey"],
ConsumerSecret = ConfigurationManager.AppSettings["twitterConsumerSecret"],
//OAuthToken = ConfigurationManager.AppSettings["twitterOAuthToken"], //don't include this
//AccessToken = ConfigurationManager.AppSettings["twitterAccessToken"] //or this for new users.
},
//
UseCompression = true,
GoToTwitterAuthorization = pageLink => Process.Start(pageLink),
GetPin = () =>
{
Console.WriteLine("/nAfter twitter authorizes your application you will be returned here or something/n");
Console.Write("Enter Pin here:");
return Console.ReadLine();
}
};
auth.Authorize();
using (var twitterCtx = new TwitterContext(auth, "https://api.twitter.com/1/",
"https://search.twitter.com/"))
{
try
{
twitterCtx.Log = Console.Out;
Console.WriteLine("Please provide tweet text");
string tweet = Console.ReadLine();
twitterCtx.UpdateStatus(tweet);
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
}
I've ran this using the Pin Authentication method as well as the single user method (providing the oauth keys with config file). I'm able to query tweets but I can't update my status or send direct messages (I receive a 403 forbidden when I try to DM). I've provided a callback URL (albeit fake) so I can't think of why this isn't working. Any help would be appreciated.
PS this runs in Main, not sure if that matters
All you need is this overload of the TwitterContext ctor and it will use the proper base URLs:
new TwitterContext(auth)
The example you're using is for v1.0 URLs and LINQ to Twitter is on Twitter API v1.1 now. It will default to the proper base URLs.
If you're querying okay, but getting errors on update and DM, double check to make sure you aren't trying to tweet the same text. That's why I append a DateTime.Now to the end of test tweets - to guarantee uniqueness.
I'm developing a desktop application in C#.
After visiting https://www.facebook.com/dialog/oauth?client_id=123 the user logs in and the user access token is attached to the redirect uri. Its no problem, when the loginpage is displayed in a webbrowser control in my form, so i can extract the token from the url.
But this is not the way i want to get the token. My question is, is there a way to obtain the freshly created token via an Graph API call?
Because i want to display the login page in the user's standard browser and not in this embedded webbrowser. All my efforts to get the user access token have been resulted in getting the app access token, which is useless in this case.
Any hints are appreciated.
// This is very raw, And Note it is a MVC3 solution, but it is in C# and I hope it helps.
// It is basically a C# version of the PHP example on FB for 'Server Side Flow'
// I have been at it for a while and had to go through some pain
// Please note the bug I read about that states the redirect_uri must be the same for both //requests
// Also read that someone had an issue if the redirect_uri did not end in '/'
// Post back if you hae any ?s as I am just starting this project and am going to try and //incorporate the C# FaceBook SDK
public class AccountController : Controller
{
// LoginWithFaceBook
// First Contact with FB - oauth?client_id ... redirect_uri = /Account/FacebookLinker
// according to a bug files on FB redirect_uri MUST BE SAME FOR both trips ( to get the 'code' then exchange the code for 'access_token'
public ActionResult ConnectFaceBookAccount()
{
string APP_ID = HttpContext.Application["FacebookAppId"].ToString();
string redirect_uri = HttpContext.Application["FacebookOAuthRedirect"].ToString();
string state = HttpContext.Application["state_guid"].ToString();
// in this View I simply link to this URL
ViewBag.FaceBookOAuthUrl = "https://www.facebook.com/dialog/oauth?client_id=" + APP_ID + "&redirect_uri="+redirect_uri+"&state=" + state+"&display=popup";
return View();
}
// Account/FacebookLinker
// redirect_uri for both getting 'code' and exchanging for 'access_token'
public ActionResult FacebookLinker()
{
if (!Request.IsAuthenticated)
{
Response.Redirect("/Account/LogOn");
}
// Per FB DOC, Make sure 'state' var returned is same one you sent to reduce chance of Cross Site Forgery
if (Request.QueryString["state"].ToString() == HttpContext.Application["state_guid"].ToString())
{
try
{
string FBcode = Request.QueryString["code"].ToString();
string APP_ID = HttpContext.Application["FacebookAppId"].ToString();
string APP_SECRET = HttpContext.Application["FacebookAppSecret"].ToString();
string redirect_uri = HttpContext.Application["FacebookOAuthRedirect"].ToString();
string FBAccessUrl = "https://graph.facebook.com/oauth/access_token?client_id=" + APP_ID + "&redirect_uri=" + redirect_uri + "&client_secret=" + APP_SECRET + "&code=" + FBcode;
string accessToken = null;
// Send the request to exchange the code for access_token
var accessTokenRequest = System.Net.HttpWebRequest.Create(FBAccessUrl);
HttpWebResponse response = (HttpWebResponse) accessTokenRequest.GetResponse();
// handle response from FB
// this will not be a url with params like the first request to get the 'code'
Encoding rEncoding = Encoding.GetEncoding(response.CharacterSet);
using(StreamReader sr = new StreamReader(response.GetResponseStream(),rEncoding))
{
// parse the response to get the value of the 'access_token'
accessToken = HttpUtility.ParseQueryString(sr.ReadToEnd()).Get("access_token");
}
//TODO
// Add to the accessToken for the Logged in User.Identity to a FBUSERS Model
// WHen someone Logs in Check to see if they are also in FB
// ON Login Page add option to login with FaceBook
return View();
}
catch (Exception exp)
{
// try to get token failed
}
}
else
{
// state var form FB did not match state var sent
}
return View();
}
I think this is achievable via URL protocol handlers;
Create a custom URL protocol handler (MSDN: Registering an Application to a URL Protocol)
Create a facebook page that passes user access token to your url handler (ex. myfbapp://accesstoken/{token})
Set oauth redirect_uri to your facebook page
Parse access token in your application