I`m a little bit confused about the Facebook Graph API.
First, I created an app on the developers page and then I autorized my app with a URL like this:
www.facebook.com/dialog/oauth?client_id=MY_CLIENT_ID&redirect_uri=http://www.facebook.com/connect/login_success.html&type=user_agent
Ok... after this the page returned an URL like this one:
www.facebook.com/connect/login_success.html#access_token=ACCESS_TOKEN&expires_in=5171411&code=CODE
I realized that the ACCESS_TOKEN returned is always the same. So i used to search for users, like this:
graph.facebook.com/search?q=QUERY_SEARCH&type=user&access_token=ACCESS_TOKEN
I believe all the URLs above are correct.
My doubt is: i don't know how to use the long-live token (actually I dont even know if the returned token is a long-lived one). The same token is always returned for me when I use those URLs, so I always use the same ACCESS_TOKEN.
But as i read on the Facebook Graph page, a token can't be active forever anymore... they now expire.
How do I know if i have a long live token or not? When a token expire how can I "refresh" it?
I was trying to follow the documentation but I`m totally lost...
developers.facebook.com/roadmap/offline-access-removal/
This page says that exists an "deprecate offline_acess" on the advanced settings menu... but it doens't!
So... i don't know how to manage tokens when they expire or how to know if i`m using a long-lived token
I think the general idea is that your access token will last a month or so, and when it stops working you need to request a new one.
I have a method like this to fetch a new one:
public static class GraphApiRequestProcessor
{
public static string GetNewAccessToken( CancellationToken cancellationToken )
{
const string tokenUrlPattern = #"https://graph.facebook.com/oauth/access_token?client_id={0}&client_secret={1}&grant_type=client_credentials";
string tokenUrl = string.Format( tokenUrlPattern, Settings.FacebookAppId, Settings.FacebookAppSecret );
using( var client = new WebClient() )
{
// allows cancellation while executing request
using( cancellationToken.Register( client.CancelAsync ) )
{
using( var data = client.OpenRead( tokenUrl ) )
{
using( var reader = new StreamReader( data ) )
{
string response = reader.ReadToEnd();
int index = response.IndexOf( "=", StringComparison.InvariantCultureIgnoreCase );
string code = response.Substring( index + 1 );
return code;
}
}
}
}
}
}
You can check when your access token is going to expire on Access Token Debugger.
You can get long-lived access tokens by using this api where you need to enter the short lived access token.
https://graph.facebook.com/oauth/access_token?
client_id=APP_ID&
client_secret=APP_SECRET&
grant_type=fb_exchange_token&
fb_exchange_token=EXISTING_ACCESS_TOKEN
where this will return the new long-lived access token. (which will have an expiry period of 2 months.)
Related
Using REST API I want to get the list of Batch Pools and Jobs.
As per the docs:
Pool - Get | Microsoft Docs - https://learn.microsoft.com/en-us/rest/api/batchservice/pool/get
Job - Get | Microsoft Docs - https://learn.microsoft.com/en-us/rest/api/batchservice/job/get
The API to get list of job is GET {batchUrl}/jobs?api-version=2019-08-01.10.0 and to get pool is GET {batchUrl}/pools?api-version=2019-08-01.10.0
In C# I am doing it like this:
client.DefaultRequestHeaders.Add("Authorization", "Bearer " + _accessToken);
using (var responseGet = client.GetAsync(api).Result) //HttpClient client
{
if (responseGet.IsSuccessStatusCode)
{
dynamic batchObjectsContent = JObject.Parse(responseGet.Content.ReadAsStringAsync().Result);
foreach (var batchObject in batchObjectsContent.value)
{
batchObjects.Add(new BatchObject { Id = batchObject.id, Url = batchObject.url, CreationTime = batchObject.creationTime, StateTransitionTime = batchObject.stateTransitionTime });
}
}
}
The complete API for getting the pool is https://mybatch.westus2.batch.azure.com/pools?api-version=2019-08-01.10.0 and api for the job is https://mybatch.westus2.batch.azure.com/jobs?api-version=2019-08-01.10.0.
Error message I am getting:
StatusCode=Unauthorized
ReasonPhrase="Server failed to authenticate the request. Make sure the value of Authorization header is formed correctly."
error="invalid_audience", error_description="The access token has been obtained from wrong audience or resource 'https://management.azure.com/'. It should exactly match (including forward slash) with one of the allowed audiences 'https://batch.core.windows.net/'"
And this is how I got the access token: authenticationContext.AcquireTokenAsync("https://management.azure.com/", credential).Result.AccessToken;. This works for all the APIs related to https://management.azure.com/.
From the errors I think there is issue with either the access token or the headers are wrong, or both. How do I correct them ?
Use the Azure Batch resource endpoint to acquire a token for authenticating requests to the Batch service:
https://batch.core.windows.net/
Use the code as below:
private const string BatchResourceUri = "https://batch.core.windows.net/";
AuthenticationResult authResult = await authContext.AcquireTokenAsync(BatchResourceUri, new ClientCredential(ClientId, ClientKey));
Refer to this article.
Coming from C# and other languages, and new to F# and trying to port an SDK Library that I built in an OO language. The SDK is responsible for retrieving access token first, setting on a static field and then setting a specific interval to continuosly refresh the token before it's expiry.
The token is set as static field on the Authentication class and is updated every time before it reaches expiry.
Then other actors within the SDK reach out to Authentication class, read it's static field token, place in their Authorization headers before calling the REST endpoints. All actors within the SDK reuse the same token throughout for each call until it's expired and a newer one is auto fetched.
That's the behavior, I'm still trying to wrap my head around several concepts but I believe in learning while doing it.
This F# library will be called from C# where it will be passed Credentials to begin with and then subsequently instantiating other classes/actors and calling their methods while passing params for each individual method. Those other actors are the one who will be using this stored token.
The gist is basically having two static fields within the Authentication and enable access to other actors while refreshing the one of the static fields i.e. Token.
public class Authentication
{
public static Token token;
public static Credentials credentials;
public static Token RequestToken(Credentials credentials)
{
Authentication.credentials = credentials // cache for subsequent use
// http REST call to access token based on credentials/api keys etc.
// Authentication.token = someAccessTokenObject; // cache result
}
public static Token AddTokenObserver(Credentials credentials)
{
this.RequestToken(credentials);
// set interval, like call RequestToken every 24 hrs
}
}
public class Class1
{
public someReturnObject RequestService1(someParams) {
// accesses Authentication.credentials
// accesses Authentication.token
// places in the authorization headers
// and calls the web service
}
// + several other methods that repeats the same pattern
}
public class Class2
{
public someReturnObject RequestService2(someParams) {
// accesses Authentication.credentials
// accesses Authentication.token
// places in the authorization headers
// and calls the web service
}
// + several other methods that repeats the same pattern
}
Use of SDK
// initialize SDK by passing credentials and enable auto refresh
Authentication.AddTokenObserver(someCredentials) // set token observer
Class1 c1 = new Class1();
c1.RequestService1(someObject1); // uses credentials & token from Authentication
Class c2 = new Class2();
c2.RequestService2(someObject2); // uses credentials & token from Authentication
My F# Attempt
type Credentials = {mutable clientId: string; mutable clientSecret: string;}
type Token = {mutable access_token: string; mutable refresh_token: string}
type Authentication =
static member token = {access_token = ""; refresh_token = ""};
static member credentials = {clientId = ""; clientSecret = "";}
new() = {}
member this.RequestToken(credentials) =
let data : byte[] = System.Text.Encoding.ASCII.GetBytes("");
let host = "https://example.com";
let url = sprintf "%s&client_id=%s&client_secret=%s" host credentials.clientId credentials.clientSecret
let request = WebRequest.Create(url) :?> HttpWebRequest
request.Method <- "POST"
request.ContentType <- "application/x-www-form-urlencoded"
request.Accept <- "application/json;charset=UTF-8"
request.ContentLength <- (int64)data.Length
use requestStream = request.GetRequestStream()
requestStream.Write(data, 0, (data.Length))
requestStream.Flush()
requestStream.Close()
let response = request.GetResponse() :?> HttpWebResponse
use reader = new StreamReader(response.GetResponseStream())
let output = reader.ReadToEnd()
printf "%A" response.StatusCode // if response.StatusCode = HttpStatusCode.OK throws an error
Authentication.credentials.clientId <- credentials.clientId
let t = JsonConvert.DeserializeObject<Token>(output)
Authentication.token.access_token <- t.access_token
Authentication.token.token_type <- t.token_type
reader.Close()
response.Close()
request.Abort()
F# Test
[<TestMethod>]
member this.TestCredentials() =
let credentials = {
clientId = "some client id";
clientSecret = "some client secret";
}
let authenticaiton = new Authentication()
try
authenticaiton.RequestToken(credentials)
printfn "%s, %s" credentials.clientId Authentication.credentials.clientId // Authentication.credentials.clientId is empty string
Assert.IsTrue(credentials.clientId = Authentication.credentials.clientId) // fails
with
| :? WebException -> printfn "error";
Question
In the above unit test
Authentication.credentials.clientId is empty string
Assert fails
I couldn't access static members within my unit tests after I called the token service. There's something wrong with how I'm approaching this all together.
I need help in translating C# behavior in F# with the help of some F# code. I've built the Authentication class and have some problems in the implementation especially around static members and subsequently accessing them. Also I want to follow the rules of functional programming and learn how it's done in Functional World in F#. Please help me translate this behavior in F# code.
The idiomatic functional approach to this problem, would be to first try to get rid of the global state.
There are several approaches to this, but the one that I think will work best would be to provide an AuthenticationContext which has the data your C# code keeps in global state, and make each call that migth renew the credentials, return its result together with a potentially updated authorization context.
Basically, given a method to make an API call with a token
type MakeApiCall<'Result> = Token -> 'Result
we want to create something like this:
type AuthenticatedCall<'Result> = AuthenticationContext -> 'Result * AuthenticationContext
You can then also let the context keep track of whether it needs renewal (e.g. by storing the timestamp when it was last renewed, storing the expiry date, or something else), and provide two functions
type NeedsRenewal = AuthenticationContext -> bool
type Renew = AuthenticationContext -> AuthenticationContext
Now, if you obtain the credentials with a function
type GetAccessToken = AuthenticationContext -> Token * AuthenticationContext
you can let the implementation of that method start by checking if the credentials need renewal, and if so renew them before returning.
So, a sample implementation might look like this:
type AuthenticationContext = {
credentials : Credentials
token : Token
expiryDate : DateTimeOffset
}
let needsRenewal context =
context.expiryDate > DateTimeOffset.UtcNow.AddMinutes(-5) // add some safety margin
let renew context =
let token = getNewToken context.Credentials
let expiryDate = DateTimeOffset.UtcNow.AddDays(1)
{ context with token = token, expiryDate = expiryDate }
let getAccessToken context =
let context' =
if needsRenewal context
then renew context
else context
return context'.token, context'
let makeAuthenticatedCall context makeApicall =
let token, context' = getAccessToken context
let result = makeApiCall token
result, context'
Now, if every time you make an API call you have access to the AuthenticationContext from the previous call, the infrastructure will take care of renewing the token for you.
You'll notice quickly that this will just push the problem to keeping track of the authentication context, and that you will have to pass that around a lot. For example, if you want to make two consecutive API calls, you'll do the following:
let context = getInitialContext ()
let resultA, context' = makeFirstCall context
let resultB, context'' = makeSecondCall context'
Wouldn't it be nice if we could build something that would keep track of the context for us, so we didn't have to pass it around?
It turns out there's a functional pattern for this situation.
I have a WebApi that I want to authorize my user with his linkedin information (as in create an access token and inject it in to my owin).
So far I have tried to work with Sparkle.Linkedin and this is what I have
public LinkedInLogic() {
// create a configuration object
_config = new LinkedInApiConfiguration(ApiKey, ApiSecret);
// get the APIs client
_api = new LinkedInApi(_config);
}
public Uri GetAuthUrl() {
var scope = AuthorizationScope.ReadBasicProfile;
var state = Guid.NewGuid().ToString();
var redirectUrl = "http://localhost:1510/api/login/RedirectAuth";
return _api.OAuth2.GetAuthorizationUrl(scope, state, redirectUrl);
}
public void GetAccessToken(string code) {
//If I do api.GetAccessToken(code); here I get an access token
var request = System.Net.WebRequest.Create("http://localhost:1510/api/token?grant_type=authorization_code&code=" + code);
request.GetResponse(); // my owin authorization
}
So I first get the Authorization Url -> it opens a popup -> I enter my data and it goes back to a controller which fires up GetAccessToken.
Problem is even if I completely authorize with linkedin I am not sure how to authorize with my own webapi. So I tried to send an http request to my owin token giver but it doesn't like it. There is also doesn't seem to be anyway I can return the access token back to the user so he can use it in his session.
Any ideas?
Not too sure if the sparkle is working anymore since the changes that where made by Linkedin on May 2015
I want to show my user feed on my website and what I intend to do is to authenticate my own user account each time a user visits the page, and in that way buypass that the user have to log in to his instagram account.
My problem is that I'm having a hard time retrieving the instagram access token through a HttpWebRequest..
See the following NON working code sample:
HttpWebRequest request = (HttpWebRequest)WebRequest.Create("https://api.instagram.com/oauth/authorize?client_id=xxxxxxxxxxxxxxxxxxxxxx&redirect_uri=http://mywebsite.com&response_type=token");
request.Method = "POST";
request.AllowAutoRedirect = false;
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
string redirectUrl = response.ResponseUri.ToString();
HttpContext.Current.Response.Write(redirectUrl);
HttpContext.Current.Response.End();
If I paste the url in my browser I get a redirect to http://mysite.com/#access_token=xxxxxxxxxxxxxx and everything seems fine, but when I try to execute the code above, I can't retrieve the correct uri due to some in between redirects before the final url.
Any help would be much appriciated..
I recommend you to use Instasharp library. InstaSharp is a C# library that wraps the Instagram API and makes it easy to write applications with Instagram data. It has a very easy method to get access token for a user. Check its API.
Unfortunately the documentation for Instasharp currently provided has a few errors. I.e. The documentation says OAuthInfo, when such a class does not exist.
Here is some code that works for me.
Notice you don't seem to need to pass a User Object at all (not sure why you would need to anyway)
Also note, that the authenticated and non authenticated methods allow you pass different params, count being the most important one. I've noticed that regardless of the count you pass, an arbitrary number of results is returned, e.g. 33 for authenticated and 13 for authenticated for the same search term. InstagramResult is my wrapper class for the object and Config holds the InstagramAuthorisationModel and InstagramAuthorisationModel holds the static keys created when signing up for a developer account.
public class InstagramService : IInstagramService
...
public InstagramConfig Config
{
get{return new InstagramConfig("https://api.instagram.com/v1", "https://api.instagram.com/oauth", InstagramAuthorisationModel.ApplicationId, InstagramAuthorisationModel.Secret, InstagramAuthorisationModel.RedirectUri);}
}
private AuthInfo UserAuthInfo()
{
return new AuthInfo()
{
// User =new UserInfo(){},
Access_Token = GetInstagramAccessToken()
};
}
public string GetInstagramAccessToken()
{
return _socialMediaRepository.GetInstagramAccessToken(_userApiKey);
}
public List<InstagramResult> Search(string searchTag, int count)
{
var auth = UserAuthInfo();
var tags = new InstaSharp.Endpoints.Tags.Authenticated(Config, auth);
var searchresult = tags.Recent(searchTag);
return searchresult.Data.Select(media => new InstagramResult()
{
Media = media,
image = media.Images.LowResolution.Url
})
.ToList();
}
..
I have a Asp.Net application that will post tweets in twitter.
I'm using Twitterizer2 for doing this.
First time when the user uses the application, he will be redirected to twitter for authentication.
And then the user-token will be stored in my application , so that the user will never be asked again to login to twitter.
This is working fine.
Now i want to validate the user-tokens before posting (ie valid token or not) . Is there any way to do this validation?
You can make a call to the Verify Credentials API
Make an authenticated call to
https://api.twitter.com/1/account/verify_credentials.json
It will respond with HTTP 200 OK if the tokens are correct - or 401 if they are not.
MoH's code didn't work for me. Here's what I did:
public bool IsTwitterAccessTokenValid(String access_token, String token_secret)
{
var token = new Twitterizer.OAuthTokens();
token.ConsumerKey = this.TwitterConsumerKey;
token.ConsumerSecret = this.TwitterConsumerSecret;
token.AccessToken = access_token;
token.AccessTokenSecret = token_secret;
var twitterResponse = TwitterAccount.VerifyCredentials(token);
return (twitterResponse.Result == RequestResult.Success);
}
I found out the code for validating tokens in another question.
The Twitterizer Api itself had the Methods to validate the User tokens.
The code is as follows:
Twitterizer.OAuthTokens token = new Twitterizer.OAuthTokens();
token.ConsumerKey = this.AppId;
token.ConsumerSecret = this.AppSecret;
token.AccessToken = userToken;
token.AccessTokenSecret = userSecret;
Twitterizer.TwitterResponse<Twitterizer.TwitterUser> response =
Twitterizer.TwitterAccount.VerifyCredentials(token);
if (String.IsNullOrEmpty(response.ErrorMessage))
{
//This is a valid token
}
else
{
//Invalid token
}