How do I generate an assertion token for Sharepoint Access on behalf of another user in C# - c#

I have a web application with a number of modules. One of the modules grabs a number of excel files from SharePoint directories, and then combines the data in them. So far, I have been just mapping the folders to OneDrive and accessing them that way. But this always uses my OneDrive credentials, which need to be refreshed from time to time. The right way to do this is to access them directly from Sharepoint on behalf of the user logged into my web application. I have the delegated API permission things set up in Azure, and I have the client ID and secret, etc.. I've been reading a number of articles on how to do this. All of them talk about how to get the token on behalf of someone else. These articles also talk about the assertion token needing to be passed in order to get the on behalf of token. However, they don't tell you how to get the assertion token in the first place. Here is the code I currently have:
'''var client = new RestClient("https://login.microsoftonline.com/XXXX/oauth2/v2.0/token");
var request = new RestRequest();
request.Method = Method.Post;
request.AddHeader("Content-Type", "application/x-www-form-urlencoded");
request.AddParameter("client_id", "MYCLIENTID", ParameterType.GetOrPost);
request.AddParameter("client_secret", "MYSECRET", ParameterType.GetOrPost);
request.AddParameter("scope", "https://MYTenent.sharepoint.com/.default", ParameterType.GetOrPost);
request.AddParameter("grant_type", "urn:ietf:params:oauth:grant-type:jwt-bearer", ParameterType.GetOrPost);
request.AddParameter("requested_token_use", "on_behalf_of", ParameterType.GetOrPost);
RestResponse response = client.Execute(request);'''
The result of this is of course an error that the assertion was not supplied. I didn't supply any more code, because I can't even get passed this. The rest of my code takes the token and passes it to an auth provider, which is then used to instantiate the GraphServiceClient. Based on what I've read, that client is then used to get the lists, files, etc...
So, my question is, how do I get the assertion token in the first place? I'm hoping the code I have written so far is in the correct direction and all I'm missing is the assertion token.
UPDATE:
I've gotten one answer that really didn't help. I pretty much copied and pasted the code (replacing the clientID, etc..) and I received an error> I was going to copy and paste it from the solution comments provided in the answer, but I guess you can't do that while editing.
Someone also asked if I was able to get the auth code from the URL. The answer to that is no. We use 2 factor authentication, and I tried to manually look at the URLS as I was logging in, while using break points to slow things down a bit. And I did not see an auth code. I did put a break point directly after the line of code:
var info = await _signInManager.GetExternalLoginInfoAsync();
And when I look at the info variable, I can see 4 tokens. One of them is an access token and another is an ID token. The last one is an expiration date. I don't see an auth code, and from what I understand, by the time I see the access code, it's too late. The auth code was already used to get the access code.
UPDATE 2:
I know that OBO is not what I want. I also know that in order to use delegated permissions, I need to use the Auth Code flow and not client credentials. I can't seem to get the auth code from the users initial log in. And I don't know how to get it otherwise.
For those of you that might be thinking "Does he need to be spoon fed?", the answer is yes, I do. I need a simple code example that will get me the auth code, so I can use it in the rest of the code I already have. If anyone can paste that code into an answer and not provide a link, that would be great. I'm sorry, but the links I have been given, just go to microsoft learn sites that go through the explaination, but don't give any code samples.

The OBO flow is obviously not applicable in your context, and if you're going to get an access token on behalf of a logged in user, then you should focus on auth code flow or ROPC flow.
The corresponding C# code segment is:
using Microsoft.Graph;
using Azure.Identity;
var scopes = new[] { "https://{tenant-name}.sharepoint.com/.default" };
// Multi-tenant apps can use "common",
// single-tenant apps must use the tenant ID from the Azure portal
var tenantId = "tenant id";
// Values from app registration
var clientId = "client id";
var clientSecret = "client secret";
// For authorization code flow, the user signs into the Microsoft
// identity platform, and the browser is redirected back to your app
// with an authorization code in the query parameters
var authorizationCode = "authorization code ";
// using Azure.Identity;
var options = new TokenCredentialOptions
{
AuthorityHost = AzureAuthorityHosts.AzurePublicCloud
};
// https://learn.microsoft.com/dotnet/api/azure.identity.authorizationcodecredential
var authCodeCredential = new AuthorizationCodeCredential(
tenantId, clientId, clientSecret, authorizationCode, options);
var accessToken = await authCodeCredential.GetTokenAsync(new Azure.Core.TokenRequestContext(scopes) { });
Console.WriteLine(accessToken.Token);
//var graphClient = new GraphServiceClient(authCodeCredential, scopes);

Related

403 Forbidden Error in Keycloak API (view-users)

I'm having issues trying to access auth/admin/realms/{realm-name}/users API. I've already tried everything from other questions and answers, but nothing seems to work. Steps that I did:
The user already has a role that has realm-management and view-users on it.
I've already assigned this same role to my client in the scopes section.
I can't have Service Accounts Enabled in my client because I need to have Access Type as confidential, and that won't allow my user to access Login page from Application.
I've also already tried to give 'view-users' role to my user and to my client individually as a Client role, it also didn't work.
My code in C#:
var authState = await AuthenticationProvider.GetAuthenticationStateAsync();
var user = authState.user;
var tokenResult = await TokenProvider.RequestAccessToken();
_accessToken = _tokenResult.Value;
_client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", _accessToken);
var request = new HttpRequestMessage(HttpMethod.Get, $"{url}/auth/admin/realms/{realm name}/users");
request.Headers.Add("Accept", "application/json");
var response = await _client.SendAsync(request);
// Rest of code that gets response and deserializes to array of users.
I honestly don't know what to do. Any help would be very appreciated. Thanks so much!
Since Keycloak's Rest API endpoints changes very often (e.g. BasePath, Signature etc.), I found very useful:
login to keycloak's admin panel (UI) and see from developer tools the endpoint for fetching the users (on Users menu item in Manage group parent). In particular, {$HOST}/admin/realms/{$REALM_NAME}/users is the endpoint in version 17.0.1.
I also assigned the client role view-users from realm-management to one of my realm users as it is displayed below (UI of version 17.0.1)
I was able to fetch the users by just adding user's access token to the request.

How to fix issue calling Amazon SP-API, which always returns Unauthorized, even with valid Token and Signature

I went through the guide of for getting setup to call the new SP-API (https://github.com/amzn/selling-partner-api-docs/blob/main/guides/developer-guide/SellingPartnerApiDeveloperGuide.md), and during the process checked off all of the api areas to grant access to (i.e. Orders, Inventory, etc). I am using the C# library provided by Amazon (https://github.com/amzn/selling-partner-api-models/tree/main/clients/sellingpartner-api-aa-csharp). I successfully get an access token and successfully sign the request, but always get the following error:
Access to requested resource is denied. / Unauthorized, with no details.
I am trying to perform a simple get to the /orders/v0/orders endpoint. What am I doing wrong?
Below is my code:
private const string MARKETPLACE_ID = "ATVPDKIKX0DER";
var resource = $"/orders/v0/orders";
var client = new RestClient("https://sellingpartnerapi-na.amazon.com");
IRestRequest restRequest = new RestRequest(resource, Method.GET);
restRequest.AddParameter("MarketPlaceIds", MARKETPLACE_ID, ParameterType.QueryString);
restRequest.AddParameter("CreatedAfter", DateTime.UtcNow.AddDays(-5), ParameterType.QueryString);
var lwaAuthorizationCredentials = new LWAAuthorizationCredentials
{
ClientId = AMAZON_LWA_CLIENT_ID,
ClientSecret = AMAZON_LWA_CLIENT_SECRET,
RefreshToken = AMAZON_LWA_REFRESH_TOKEN,
Endpoint = new Uri("https://api.amazon.com/auth/o2/token")
};
restRequest = new LWAAuthorizationSigner(lwaAuthorizationCredentials).Sign(restRequest);
var awsAuthenticationCredentials = new AWSAuthenticationCredentials
{
AccessKeyId = AMAZON_ACCESS_KEY_ID,
SecretKey = AMAZON_ACCESS_SECRET,
Region = "us-east-1"
};
restRequest = new AWSSigV4Signer(awsAuthenticationCredentials).Sign(restRequest, client.BaseUrl.Host);
var response = client.Execute(restRequest);
If you followed the SP-API guide, then you created a Role (which is the IAM ARN your app is registered with) and a User which has permissions to assume that role to make API calls.
However, one thing the guide is not clear about is that you can't make API calls using that user's credentials directly. You must first call the STS API's AssumeRole method with your User's credentials (AMAZON_ACCESS_KEY_ID/AMAZON_ACCESS_SECRET), and it will return temporary credentials authorized against the Role. You use those temporary credentials when signing requests.
AssumeRole will also return a session token which you must include with your API calls in a header called X-Amz-Security-Token. For a brief description of X-Amz-Security-Token see https://docs.aws.amazon.com/STS/latest/APIReference/CommonParameters.html
You also get this error if your sp app is under review, drove me nuts!
If you using c# take look to
https://github.com/abuzuhri/Amazon-SP-API-CSharp
AmazonConnection amazonConnection = new AmazonConnection(new AmazonCredential()
{
AccessKey = "AKIAXXXXXXXXXXXXXXX",
SecretKey = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
RoleArn = "arn:aws:iam::XXXXXXXXXXXXX:role/XXXXXXXXXXXX",
ClientId = "amzn1.application-XXX-client.XXXXXXXXXXXXXXXXXXXXXXXXXXXX",
ClientSecret = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
RefreshToken= "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
});
var orders= amazonConnection.Orders.ListOrders();
In our situation, we had to explicitly add an IAM policy to the user we defined as making the API call. Please see the link below and confirm that the user you have calling the API has the policy assigned to them:
https://github.com/amzn/selling-partner-api-docs/blob/main/guides/developer-guide/SellingPartnerApiDeveloperGuide.md#step-3-create-an-iam-policy
Somehow we went through the step-by-step setup twice, and adding this explicit policy was missed. Initially I believe it was added 'inline' as instructed, but that does not seem to work.
I dont think is a duplicated question, buy the solution may apply: https://stackoverflow.com/a/66860192/1034622

Microsoft Graph The token contains no permissions, or permissions cannot be understood

I am working with Microsoft Graph and have created an app that reads mail from a specific user.
However, after getting an access token and trying to read the mailfolders, I receive a 401 Unauthorized answer. The detail message is:
The token contains no permissions, or permissions cannot be understood.
This seems a pretty clear message, but unfortunately I am unable to find a solution.
This is what I have done so far:
Registering the app on https://apps.dev.microsoft.com
Giving it
application permissions Mail.Read, Mail.ReadWrite
(https://learn.microsoft.com/en-us/graph/api/user-list-mailfolders?view=graph-rest-1.0)
Have gotten administrator consent.
The permissions are:
- Written the code below to acquire an access token:
// client_secret retrieved from secure storage (e.g. Key Vault)
string tenant_id = "xxxx.onmicrosoft.com";
ConfidentialClientApplication client = new ConfidentialClientApplication(
"..",
$"https://login.microsoftonline.com/{tenant_id}/",
"https://dummy.example.com", // Not used, can be any valid URI
new ClientCredential(".."),
null, // Not used for pure client credentials
new TokenCache());
string[] scopes = new string[] { "https://graph.microsoft.com/.default" };
AuthenticationResult result = client.AcquireTokenForClientAsync(scopes).Result;
string token = result.AccessToken;
So far so good. I do get a token.
Now I want to read the mail folders:
url = "https://graph.microsoft.com/v1.0/users/{username}/mailFolders";
handler = (HttpWebRequest)WebRequest.Create(url);
handler.Method = "GET";
handler.ContentType = "application/json";
handler.Headers.Add("Authorization", "Bearer " + token);
response = (HttpWebResponse)handler.GetResponse();
using (StreamReader sr = new StreamReader(response.GetResponseStream()))
{
returnValue = sr.ReadToEnd();
}
This time I receive a 401 message, with the details:
The token contains no permissions, or permissions cannot be understood.
I have searched the internet, but can’t find an answer to why my token has no permissions.
Thanks for your time!
update 1
If I use Graph Explorer to read the mailfolders, then it works fine. Furthermore: if I grap the token id from my browser en use it in my second piece of code, then I get a result as well. So, the problem is really the token I receive from the first step.
To ensure this works like you expect, you should explicitly state for which tenant you wish to obtain the access token. (In this tenant, the application should, of course, have already obtained admin consent.)
Instead of the "common" token endpoint, use a tenant-specific endpoint:
string url = "https://login.microsoftonline.com/{tenant-id}/oauth2/v2.0/token";
(Where {tenant-id} is either the tenant ID of the tenant (a Guid), or any verified domain name.)
I would also strongly recommend against building the token request on your own, as you show in your question. This may be useful for educational purposes, but will tend to be insecure and error-prone in the long run.
There are various libraries you can use for this instead. Below, an example using the Microsoft Authentication Library (MSAL) for .NET:
// client_secret retrieved from secure storage (e.g. Key Vault)
string tenant_id = "contoso.onmicrosoft.com";
ConfidentialClientApplication client = new ConfidentialClientApplication(
client_id,
$"https://login.microsoftonline.com/{tenant_id}/",
"https://dummy.example.com", // Not used, can be any valid URI
new ClientCredential(client_secret),
null, // Not used for pure client credentials
new TokenCache());
string[] scopes = new string[] { "https://graph.microsoft.com/.default" };
AuthenticationResult result = client.AcquireTokenForClientAsync(scopes).Result
string token = result.AccessToken;
// ... use token

Differences between AcquireTokenAsync and LoginAsync in Xamarin Native

TL;DR
What is the difference between authenticating users with AuthenticationContext.AcquireTokenAsync() and MobileServiceClient.LoginAsync() ?
Can I use the token from the first method to authenticate a user in the second?
Long Version
I've been trying to authenticate users via a mobile device (iOS) for a mobile service in Azure with Xamarin Native (not Forms).
There are enough tutorials online to get you started but in the process, I got lost and confused...
What's working at the moment is the following; which has the user enter his credentials in another page and returns a JWT token which (if decoded here1) has the claims listed here2.
Moreover, this token is authorized in controllers with the [Authorize] attribute in requests with an Authorization header and a Bearer token.
Note: the following constants are taken from the registered applications in Active Directory (Native and Web App / API).
public const string Authority = #"https://login.windows.net/******.com";
public const string GraphResource = #"https://*******.azurewebsites.net/********";
public const string ClientId = "046b****-****-****-****-********0290";
public const string Resource = #"https://******.azurewebsites.net/.auth/login/done";
var authContext = new AuthenticationContext(Authority);
if (authContext.TokenCache.ReadItems().Any(c => c.Authority == Authority))
{
authContext = new AuthenticationContext(authContext.TokenCache.ReadItems().First().Authority);
}
var uri = new Uri(Resource);
var platformParams = new PlatformParameters(UIApplication.SharedApplication.KeyWindow.RootViewController);
AuthenticationResult authResult = await authContext.AcquireTokenAsync(GraphResource, ClientId, uri, platformParams);
Another working authentication flow I tried is the following; which does the same with the difference that it informs the user that the app requires permissions to access some resources.
If allowed, a JWT token (with less characters than the previous one) is returned with less payload data. This token though, won't pass the authorization attribute just like the previous one.
public const string AadResource = #"https://******.azurewebsites.net/.auth/aad";
var client = new MobileServiceClient(AadResource);
var rootView = UIApplication.SharedApplication.KeyWindow.RootViewController;
MobileServiceUser user = await client.LoginAsync(rootView, "aad");
Obviously, the return type is different, but, what is the main difference between these two authentication methods?
Additionally, another headache comes from trying to achieve this3 at the very end of the article. I already have the token from the first aforementioned method but when I try to follow the client flow with the token in client.LoginAsync() the following error is returned:
The resource you are looking for has been removed, had its name changed, or is temporarily unavailable.
Link References:
https://jwt.io/
https://learn.microsoft.com/en-us/azure/active-directory/develop/active-directory-token-and-claims
https://adrianhall.github.io/develop-mobile-apps-with-csharp-and-azure/chapter2/enterprise/
https://www.reddit.com/r/xamarindevelopers/comments/6dw928/differences_between_acquiretokenasync/
Edit (30 May 2017)
The Why are they different? has been answered on this4 reddit post by the same person (pdx mobilist / saltydogdev) and the simple answer is claims.
Yes. You can insert a token into the MobileServicesClient and then use it had been authenticated directly. That's the beauty of bearer tokens.
Just set the MobileServiceClient CurrentUser:
MobileServiceclient Client;
...
Client.CurrentUser = new MobileServiceUser(username)
{ MobileServiceAuthenticationToken = authtoken};
Edit:
The reason they are different is because each library is requesting a different set of claims. The reason they still work is that the basic information for authenticating/validating the token is there. I'm not sure what are the specific required claims. At a minimum it would be the user id AND that the signature is valid. They are doing the same basic thing, MobileServiceClient just requests less claims.
I believe that the MobileServicesClient can authenticate against Azure AD, if you set up the mobile service correctly. So you should be able to just use the MobileServiceClient.
Here is the document that describes how this works: https://learn.microsoft.com/en-us/azure/app-service-mobile/app-service-mobile-how-to-configure-active-directory-authentication

OAuth authentication without browser [duplicate]

I'm trying to create a .NET-based client app (in WPF - although for the time being I'm just doing it as a console app) to integrate with an OAuth-enabled application, specifically Mendeley (http://dev.mendeley.com), which apparently uses 3-legged OAuth.
This is my first time using OAuth, and I'm having a lot of difficulty getting started with it. I've found several .NET OAuth libraries or helpers, but they seem to be more complicated than I think I need. All I want to do is be able to issue REST requests to the Mendeley API and get responses back!
So far, I've tried:
DotNetOpenAuth
http://github.com/bittercoder/DevDefined.OAuth
http://oauth.googlecode.com/svn/code/csharp/
The first (DotNetOpenAuth) seems like it could possibly do what I needed if I spent hours and hours trying to work out how. The second and third, as best I can tell, don't support the verification codes that Mendeley is sending back -- although I could be wrong about this :)
I've got a consumer key and secret from Mendeley, and with DotNetOpenAuth I managed to get a browser launched with the Mendeley page providing a verification code for the user to enter into the application. However, at this point I got lost and couldn't work out how to sensibly provide that back to the application.
I'm very willing to admit that I have no idea where to start with this (although it seems like there's quite a steep learning curve) - if anyone can point me in the right direction I'd appreciate it!
I agree with you. The open-source OAuth support classes available for .NET apps are hard to understand, overly complicated (how many methods are exposed by DotNetOpenAuth?), poorly designed (look at the methods with 10 string parameters in the OAuthBase.cs module from that google link you provided - there's no state management at all), or otherwise unsatisfactory.
It doesn't need to be this complicated.
I'm not an expert on OAuth, but I have produced an OAuth client-side manager class, that I use successfully with Twitter and TwitPic. It's relatively simple to use. It's open source and available here: Oauth.cs
For review, in OAuth 1.0a...kinda funny, there's a special name and it looks like a "standard" but as far as I know the only service that implements "OAuth 1.0a" is Twitter. I guess that's standard enough. ok, anyway in OAuth 1.0a, the way it works for desktop apps is this:
You, the developer of the app, register the app and get a "consumer key" and "consumer secret". On Arstechnica, there's a well written analysis of why this model isn't the best, but as they say, it is what it is.
Your app runs. The first time it runs, it needs to get the user to explicitly grant approval for the app to make oauth-authenticated REST requests to Twitter and its sister services (like TwitPic). To do this you must go through an approval process, involving explicit approval by the user. This happens only the first time the app runs. Like this:
request a "request token". Aka temporary token.
pop a web page, passing that request token as a query param. This web page presents UI to the user, asking "do you want to grant access to this app?"
the user logs in to the twitter web page, and grants or denies access.
the response html page appears. If the user has granted access, there's a PIN displayed in a 48-pt font
the user now needs to cut/paste that pin into a windows form box, and click "Next" or something similar.
the desktop app then does an oauth-authenticated request for an "Access token". Another REST request.
the desktop app receives the "access token" and "access secret".
After the approval dance, the desktop app can just use the user-specific "access token" and "access secret" (along with the app-specific "consumer key" and "consumer secret") to do authenticated requests on behalf of the user to Twitter. These don't expire, although if the user de-authorizes the app, or if Twitter for some reason de-authorizes your app, or if you lose your access token and/or secret, you'd need to do the approval dance again.
If you're not clever, the UI flow can sort of mirror the multi-step OAuth message flow. There is a better way.
Use a WebBrowser control, and open the authorize web page within the desktop app. When the user clicks "Allow", grab the response text from that WebBrowser control, extract the PIN automatically, then get the access tokens. You send 5 or 6 HTTP requests but the user needs to see only a single Allow/Deny dialog. Simple.
Like this:
If you've got the UI sorted, the only challenge that remains is to produce oauth-signed requests. This trips up lots of people because the oauth signing requirements are sort of particular. That's what the simplified OAuth Manager class does.
Example code to request a token:
var oauth = new OAuth.Manager();
// the URL to obtain a temporary "request token"
var rtUrl = "https://api.twitter.com/oauth/request_token";
oauth["consumer_key"] = MY_APP_SPECIFIC_KEY;
oauth["consumer_secret"] = MY_APP_SPECIFIC_SECRET;
oauth.AcquireRequestToken(rtUrl, "POST");
THAT'S IT. Simple. As you can see from the code, the way to get to oauth parameters is via a string-based indexer, something like a dictionary. The AcquireRequestToken method sends an oauth-signed request to the URL of the service that grants request tokens, aka temporary tokens. For Twitter, this URL is "https://api.twitter.com/oauth/request_token". The oauth spec says you need to pack up the set of oauth parameters (token, token_secret, nonce, timestamp, consumer_key, version, and callback), in a certain way (url-encoded and joined by ampersands), and in a lexicographically-sorted order, generate a signature on that result, then pack up those same parameters along with the signature, stored in the new oauth_signature parameter, in a different way (joined by commas). The OAuth manager class does this for you automatically. It generates nonces and timestamps and versions and signatures automatically - your app doesn't need to care or be aware of that stuff. Just set the oauth parameter values and make a simple method call. the manager class sends out the request and parses the response for you.
Ok, then what? Once you get the request token, you pop the web browser UI in which the user will explicitly grant approval. If you do it right, you'll pop this in an embedded browser. For Twitter, the URL for this is "https://api.twitter.com/oauth/authorize?oauth_token=" with the oauth_token appended. Do this in code like so:
var url = SERVICE_SPECIFIC_AUTHORIZE_URL_STUB + oauth["token"];
webBrowser1.Url = new Uri(url);
(If you were doing this in an external browser you'd use System.Diagnostics.Process.Start(url).)
Setting the Url property causes the WebBrowser control to navigate to that page automatically.
When the user clicks the "Allow" button a new page will be loaded. It's an HTML form and it works the same as in a full browser. In your code, register a handler for the DocumentedCompleted event of the WebBrowser control, and in that handler, grab the pin:
var divMarker = "<div id=\"oauth_pin\">"; // the div for twitter's oauth pin
var index = webBrowser1.DocumentText.LastIndexOf(divMarker) + divMarker.Length;
var snip = web1.DocumentText.Substring(index);
var pin = RE.Regex.Replace(snip,"(?s)[^0-9]*([0-9]+).*", "$1").Trim();
That's a bit of HTML screen scraping.
After grabbing the pin, you don't need the web browser any more, so:
webBrowser1.Visible = false; // all done with the web UI
...and you might want to call Dispose() on it as well.
The next step is getting the access token, by sending another HTTP message along with that pin. This is another signed oauth call, constructed with the oauth ordering and formatting I described above. But once again this is really simple with the OAuth.Manager class:
oauth.AcquireAccessToken(URL_ACCESS_TOKEN,
"POST",
pin);
For Twitter, that URL is "https://api.twitter.com/oauth/access_token".
Now you have access tokens, and you can use them in signed HTTP requests. Like this:
var authzHeader = oauth.GenerateAuthzHeader(url, "POST");
...where url is the resource endpoint. To update the user's status, it would be "http://api.twitter.com/1/statuses/update.xml?status=Hello".
Then set that string into the HTTP Header named Authorization.
To interact with third-party services, like TwitPic, you need to construct a slightly different OAuth header, like this:
var authzHeader = oauth.GenerateCredsHeader(URL_VERIFY_CREDS,
"GET",
AUTHENTICATION_REALM);
For Twitter, the values for the verify creds url and realm are "https://api.twitter.com/1/account/verify_credentials.json", and "http://api.twitter.com/" respectively.
...and put that authorization string in an HTTP header called X-Verify-Credentials-Authorization. Then send that to your service, like TwitPic, along with whatever request you're sending.
That's it.
All together, the code to update twitter status might be something like this:
// the URL to obtain a temporary "request token"
var rtUrl = "https://api.twitter.com/oauth/request_token";
var oauth = new OAuth.Manager();
// The consumer_{key,secret} are obtained via registration
oauth["consumer_key"] = "~~~CONSUMER_KEY~~~~";
oauth["consumer_secret"] = "~~~CONSUMER_SECRET~~~";
oauth.AcquireRequestToken(rtUrl, "POST");
var authzUrl = "https://api.twitter.com/oauth/authorize?oauth_token=" + oauth["token"];
// here, should use a WebBrowser control.
System.Diagnostics.Process.Start(authzUrl); // example only!
// instruct the user to type in the PIN from that browser window
var pin = "...";
var atUrl = "https://api.twitter.com/oauth/access_token";
oauth.AcquireAccessToken(atUrl, "POST", pin);
// now, update twitter status using that access token
var appUrl = "http://api.twitter.com/1/statuses/update.xml?status=Hello";
var authzHeader = oauth.GenerateAuthzHeader(appUrl, "POST");
var request = (HttpWebRequest)WebRequest.Create(appUrl);
request.Method = "POST";
request.PreAuthenticate = true;
request.AllowWriteStreamBuffering = true;
request.Headers.Add("Authorization", authzHeader);
using (var response = (HttpWebResponse)request.GetResponse())
{
if (response.StatusCode != HttpStatusCode.OK)
MessageBox.Show("There's been a problem trying to tweet:" +
Environment.NewLine +
response.StatusDescription);
}
OAuth 1.0a is sort of complicated under the covers, but using it doesn't need to be.
The OAuth.Manager handles the generation of outgoing oauth requests, and the receiving and processing of oauth content in the responses. When the Request_token request gives you an oauth_token, your app doesn't need to store it. The Oauth.Manager is smart enough to do that automatically. Likewise when the access_token request gets back an access token and secret, you don't need to explicitly store those. The OAuth.Manager handles that state for you.
In subsequent runs, when you already have the access token and secret, you can instantiate the OAuth.Manager like this:
var oauth = new OAuth.Manager();
oauth["consumer_key"] = CONSUMER_KEY;
oauth["consumer_secret"] = CONSUMER_SECRET;
oauth["token"] = your_stored_access_token;
oauth["token_secret"] = your_stored_access_secret;
...and then generate authorization headers as above.
// now, update twitter status using that access token
var appUrl = "http://api.twitter.com/1/statuses/update.xml?status=Hello";
var authzHeader = oauth.GenerateAuthzHeader(appUrl, "POST");
var request = (HttpWebRequest)WebRequest.Create(appUrl);
request.Method = "POST";
request.PreAuthenticate = true;
request.AllowWriteStreamBuffering = true;
request.Headers.Add("Authorization", authzHeader);
using (var response = (HttpWebResponse)request.GetResponse())
{
if (response.StatusCode != HttpStatusCode.OK)
MessageBox.Show("There's been a problem trying to tweet:" +
Environment.NewLine +
response.StatusDescription);
}
You can download a DLL containing the OAuth.Manager class here. There is also a helpfile in that download. Or you can view the helpfile online.
See an example of a Windows Form that uses this manager here.
WORKING EXAMPLE
Download a working example of a command-line tool that uses the class and technique described here:

Categories