is there a way to associate a spotify access token to a ASP.NET identity user? - c#

I'm working on a multilanguage project for accademic purpose. I've written a simple Python Client that make requests to an API server written in ASP.NET. The server retrives spotify info about users. The server interacts with a DB filled by a Golang server that only makes scraping on API's exposed from Spotify. I'm aware that it's a misuse and there are better solutions
Clearly, Golang server, in order to make requests to Spotify API's, needs to know the access token returned from spotify Authorization Code Flow. Overlooking about spotify token expire time, the idea is: after user authentication through Identity module of ASP.NET server (using JWT token), associate the access token obtained calling https://accounts.spotify.com/api/token to user's informations. So, i expose an API in ASP.NET server like this
[AllowAnonymous]
[HttpPost("token")]
public async Task<ContentResult> getTokenAsync(string? code = null)
{
//to retrive information about who is the user that making call -> need later for associate spotifytoken
string accessToken = Request.Headers[HeaderNames.Authorization].ToString().Replace("Bearer ", "");
JwtSecurityTokenHandler t = new JwtSecurityTokenHandler();
var token = t.ReadJwtToken(accessToken);
var user = _userManager.FindByIdAsync(token.Subject).Result;
string s = "https://accounts.spotify.com/api/token";
if (code == null)
{
var qb = new QueryBuilder();
qb.Add("response_type", "code");
qb.Add("client_id", _config["SpotiSetting:clientId"]);
qb.Add("scope", "user-read-private user-read-email user-library-read");
qb.Add("redirect_uri", _config["SpotiSetting:redirectUser"]);
qb.Add("show_dialog", "true");
return new ContentResult
{
ContentType = "text/html",
Content = "https://accounts.spotify.com/authorize/" + qb.ToQueryString().ToString()
//Content = JsonConvert.SerializeObject(user.Result)
};
} else
{
//if i'm here, api is the callback designed for spotify
var qb = new QueryBuilder();
qb.Add("grant_type", "authorization_code");
qb.Add("code", code);
qb.Add("redirect_uri", "https://localhost:44345/spotify/token");
var client = new HttpClient();
var req = new HttpRequestMessage(HttpMethod.Post, s);
req.Content = new FormUrlEncodedContent(qb);
req.Headers.Authorization = new AuthenticationHeaderValue("Basic", "here_my_secret_encoded_CLIENTID:CLIENT_SECRET");
var response = await client.SendAsync(req);
var result = response.Content.ReadAsStringAsync().Result;
AccessToken json = JsonConvert.DeserializeObject<AccessToken>(result);
user.spotifyInformation.authToken = code;
user.spotifyInformation.accessToken = json;
var res = _userManager.UpdateAsync(user);
if (res.IsCompletedSuccessfully)
{
return Content("ok");
}
else
{
Content("Problem");
}
} return Content("");
}
The problem is that the second time that API is invoked, it's spotify that is sending the first authorization token (needed to request access_token), so I lost user information retrived in the first request. Should be better write two distinct API and separate callback from user request?
It's my first question here, so please to have mercy

Related

Getting 401 (Unauthorized) error in Active Directory user image in Multi tenant Application

I have implemented Multi tenant application using Azure Active Directory in Angular 4.After user logged into my application i'm able get user info.But user photo is not getting from the Active directory for that i have implemented Graph API like below snippet.
public Task<UserDto> getPhoto(TenantDto tenantDto)
{
var client = new HttpClient();
client.BaseAddress = new Uri(String.Format("https://graph.windows.net/{0}/users/{1}/thumbnailPhoto?api-version=1.6", tenantDto.tenantKey, tenantDto.email));
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("image/jpeg"));
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", tenantDto.token);
HttpResponseMessage response = client.GetAsync("").Result;
if (response.IsSuccessStatusCode)
{
return null;
//Status status = response.Content.ReadAsAsync<Status>().Result;
//if (status.Code == 200)
// InBoundResponse = JsonConvert.DeserializeObject<InBoundCallResponse>(status.Data.ToString());
//return InBoundResponse;
}
else
{
return null;
}
}
Here tenantDto.token is nothing but a logged in user "token" While calling this Graph API i'm getting 401 (Unauthorized) error. I have tried all but no use.
I have changed Graph API setting s in Active Directory APP also like below attachment
Also i have tried like below code it's working only for single tenant
[Route("AdUserImage"), HttpGet]
public async Task<HttpResponseMessage> userImage()
{
var authContext = new AuthenticationContext("https://login.windows.net/sampletest.onmicrosoft.com/oauth2/token");
var credential = new ClientCredential(clientID, clientSecret);
ActiveDirectoryClient directoryClient = new ActiveDirectoryClient(serviceRoot, async () =>
{
var result = await authContext.AcquireTokenAsync("https://graph.windows.net/", credential);
return result.AccessToken;
});
var user = await directoryClient.Users.Where(x => x.UserPrincipalName == "balu#sampletest.onmicrosoft.com").ExecuteSingleAsync();
DataServiceStreamResponse photo = await user.ThumbnailPhoto.DownloadAsync();
using (MemoryStream s = new MemoryStream())
{
photo.Stream.CopyTo(s);
var encodedImage = Convert.ToBase64String(s.ToArray());
}
//string token = await HttpAppAuthenticationAsync();
Status status = new Status("OK");
status = new Status("Found", null, "User exists.");
return Request.CreateResponse(HttpStatusCode.OK, status, _jsonMediaTypeFormatter);
}
but i need to implement for Multi tenant app.
Any Answer Appreciated.
Thanks in Advance........!
Delegate-user token:
1 .Acquire the token via the implict flow:
https://login.microsoftonline.com/{tenant}/oauth2/authorize?response_type=token&client_id={clientId}&redirect_uri={redirect_uri}&resource=https%3A%2F%2Fgraph.windows.net&nonce={nonce}
2 .Call the Azure AD Graph
GET: https://graph.windows.net/{tenant}/me/thumbnailPhoto?api-version=1.6
Content-Type: image/jpeg
Application token:
1 .Acquire the token via the client credentials flow
POST:https://login.microsoftonline.com/{tenant}/oauth2/token
grant_type=client_credentials&client_id={client_id}&client_secret={client_secret}&resource=https%3A%2F%2Fgraph.windows.net
2 .Call the Azure AD Graph
GET:https://graph.windows.net/{tenant}/users/{upn}/thumbnailPhoto?api-version=1.6
Content-Type: image/jpeg
If you only to get the thumbnail photo of sign-in user for the multiple tenant, you should login-in with Azure AD first and acquire the access token for the delegate user and used that token to call Azure AD Graph REST. Difference between these two kinds of token, you can refer the links below:
Get access on behalf of a user
Get access without a user
I'm using Delegate-user token as per your explnation using below url
https://login.microsoftonline.com/{tenant}/oauth2/authorize?response_type=token&client_id={clientId}&redirect_uri={redirect_uri}&resource=https%3A%2F%2Fgraph.windows.net&nonce={nonce}
But still not able receiving but i'm able getting 200 status but token is not return.i have implemented like below
var client = new HttpClient();
client.BaseAddress = new Uri("https://login.microsoftonline.com/{TenantID}/oauth2/authorize?response_type=token&client_id={ClientID}&redirect_uri={ApplicationUrl}&resource=https%3A%2F%2Fgraph.windows.net&nonce=a9d7730c-79f3-4092-803a-07f346de2cdf");
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("text/html"));
HttpResponseMessage response = client.GetAsync("").Result;
if (response.IsSuccessStatusCode)
{
}
else
{
//return null;
}
It's not return the token.it is returning html content in success block

How to get "user" access token in a Web API using Facebook C# SDK?

I am developing a web API to handle realtime updates (Lead information) from Facebook to integrate with my CRM.
In the WEB API POST request, I am able to capture the leadID but the problem comes when I get leadinfo by invoking FB.Get(LeadID). To make a Graph API GET request(for lead information) I need to have a user access token and this is where i have been struggling for quite sometime. I have looked up several posts online but havent got any solution for my problem.
In my sample implementation, GetLoginUrl(parameters) returns a uri and when when I request the uri in a browser, I see that the access token gets generated in the redirected Uri. But how to do this programatically ? I have tried the following
string FBAccessUrl = "https://graph.facebook.com/oauth/authorize?client_id=XXXXXXXXXXXX&response_type=token&redirect_uri=https://www.facebook.com/connect/login_success.html";
var accessTokenRequest = System.Net.HttpWebRequest.Create(FBAccessUrl);
HttpWebResponse response = (HttpWebResponse)accessTokenRequest.GetResponse();
but then i get this ResponseUri = {https://www.facebook.com/unsupportedbrowser} which is not what I want.
Can someone help me with how the user access token can be generated using C# in the Web API (without the facebook login dialog)
[HttpPost]
[ActionName("Complex")]
public void PostComplex(RootObject root)
{
FacebookClient fb = new FacebookClient();
// Get leadID from the inital HTTP POST request
long leadgen_id = root.entry[0].changes[0].value.leadgen_id;
string leadID = leadgen_id.ToString();
// to get user access token
dynamic parameters = new ExpandoObject();
parameters.client_id = "XXXXXXXXXXXXXXX";
parameters.redirect_uri = "https://www.facebook.com/connect/login_success.html";
parameters.response_type = "token";
// generate the login url
Uri uri = fb.GetLoginUrl(parameters);
// reuest the uri in browser and uri2 is the redirected uri
Uri uri2 = "****************"
string accesstoken = "";
FacebookOAuthResult oauthResult;
if (fb.TryParseOAuthCallbackUrl(uri, out oauthResult))
{
if (oauthResult.IsSuccess)
{
accesstoken = oauthResult.AccessToken;
}
else
{
var errorDescription = oauthResult.ErrorDescription;
var errorReason = oauthResult.ErrorReason;
}
}
fb.AccessToken = accesstoken;
string me = fb.Get(leadID).ToString();
// Then fetch required lead information
}

Using Facebook SDK to publish on user feed / wall

I'm trying to understand if it is possible to post on the users' wall from my Facebook application.
At the moment I have:
One Facebook app with the permission to write on the users' wall
A BackEnd with Fairbooks SDK Installed
Actually I'm following this approach:
public static string GetToken()
{
var fb = new Facebook.FacebookClient();
dynamic result = fb.Get("oauth/access_token", new
{
client_id = APP_ID,
client_secret = APP_S,
grant_type = "client_credentials"
});
return result.access_token;
}
public static void Post(string Message, long UserID)
{
var token = GetToken();
var client = new FacebookClient(token);
client.Post("/" + UserID + "/photos", new { url = "url", caption = Message });
}
My final goal is to post on facebook when the user interact with my API without client-side popups. Is this possible?
This line of code calls for an application access token
dynamic result = fb.Get("oauth/access_token", new
{
client_id = APP_ID,
client_secret = APP_S,
grant_type = "client_credentials"
});
It makes no sense to use this if you haven't first retrieved a user access token in advance. Only then can you make calls on behalf of the user.
My final goal is to post on facebook when the user interact with my API without client-side popups. Is this possible?
This will never be possible by design. All 3rd party applications must invoke a client-side activity for the user in some format. It cannot be automated.

Posting to FB Page error(s)

Scenario: I want to get user access token of the fb page admin by JS login and retrieving token ONE TIME, and will store that in database. Then daily, I want to do wall post to those page.
I am using JS to get the initial token and storing it. Then using c# FacebookSDK for the web requests.
FB.login(function (response) {
var r = response;
// get access token of the user and update in database
$("#FacebookAccessToken").val(response.authResponse.accessToken);
},
{
scope: 'manage_pages,publish_stream'
});
Now I am saving this token in database as I will be using this for future graph calls - is this right?
On server side when I need to do a post after a day I retrieve that token and do the processing as below:
// step 1 get application access token
var fb1 = new FacebookClient();
dynamic appTokenCLient = fb1.Get("oauth/access_token", new
{
client_id = appId,
client_secret = appSecret,
grant_type = "client_credentials",
scope = "manage_pages,publish_stream",
redirect_uri = siteUrl
});
var fbTokenSettingVal = GetTokenFromDB(); // getting access token from database which was stored during JS fb login
// step 2 extend token
var fb2 = new FacebookClient(appTokenCLient.access_token);
dynamic extendedToken = fb2.Get("oauth/access_token", new
{
client_id = appId,
client_secret = appSecret,
grant_type = "fb_exchange_token",
fb_exchange_token = fbTokenSettingVal.Val
});
var userExtendedToken = extendedToken.access_token; // get extended token and update database
// step 3 get page access token from the pages, that the user manages
var fb3 = new FacebookClient { AppId = appId, AppSecret = appSecret, AccessToken = userExtendedToken };
var fbParams = new Dictionary<string, object>();
var publishedResponse = fb3.Get("/me/accounts", fbParams) as JsonObject;
var data = JArray.Parse(publishedResponse["data"].ToString());
var pageToken = "";
foreach (var account in data)
{
if (account["name"].ToString().ToLower().Equals("PAGE_NAME"))
{
pageToken = account["access_token"].ToString();
break;
}
}
// step 4 post a link to the page - throws error !
var fb4 = new FacebookClient(pageToken);
fb4.Post("/PAGE_NAME/feed",
new
{
link = "http://www.stackoverflow.com"
});
The last 4th step throws error, when posting to selected page:
The user hasn't authorized the application to perform this action
Have tried several different ways, but in vain. Assume that there is just a simple step which I am doing wrong here.
Also, is it ok to extend the fb access token for user every time before making request?
Any way to check if token is expired or not?
If you want to use that access token for future. You need to take offline_access token and that token you need to store in database.
This offline accesstoken will be expire once user will change the password or delete your application from facebook account.
private void GetPermenentAccessTokenOfUser(string accessToken)
{
var client2 = new FacebookClient(accessToken);
//get permenent access token
dynamic result = client2.Post("oauth/access_token", new
{
client_id = _apiKey,
client_secret = _apiSecret,
grant_type = "fb_exchange_token",
fb_exchange_token = accessToken
});
_accessToken = result.access_token;
}
Looks like for new apps we need to apply for manage_pages permission from our application:
which I am doing now. As it shows error when doing login:
Also, the app needs to be live, so they can reproduce this permission and verify that we do need this permission to post to pages. Its good for fb users safety but a time taking process for developers.
Any way this can be skipped for testing purpose?

Want to request authorization to gmail with dotnetOpenAuth

I use dotnetOpenAuth. I want to request authorization to the user's gamil.
Do I need to use openId first?
Cannot find a decent tutorail. Can anyone help?
Tried this code unsuccesfully. Anyway I don't seems to ask for Gmail scope at the auth request, so I'm confused
public void PrepareAuthorizationRequest(Uri authCallbakUrl)
{
var consumer = new WebConsumer(GoogleConsumerConsts.ServiceDescription, mConsumerTokenManager);
// request access
consumer.Channel.Send(consumer.PrepareRequestUserAuthorization(authCallbakUrl, null, null));
throw new NoRedirectToAuthPageException();
}
public ProcessAuthorizationRequestResponse ProcessAuthorizationRequest()
{
ProcessAuthorizationRequestResponse response;
// Process result from the service provider
var consumer = new WebConsumer(GoogleConsumerConsts.ServiceDescription, mConsumerTokenManager);
var accessTokenResponse = consumer.ProcessUserAuthorization();
// If we didn't have an access token response, this wasn't called by the service provider
if (accessTokenResponse == null)
response = new ProcessAuthorizationRequestResponse
{
IsAuthorized = false
};
else
{
// Extract the access token
string accessToken = accessTokenResponse.AccessToken;
response = new ProcessAuthorizationRequestResponse
{
IsAuthorized = true,
Token = accessToken,
Secret = mConsumerTokenManager.GetTokenSecret(accessToken)
};
}
return response;
}
private string Test2()
{
// Process result from linked in
var google = new WebConsumer(GoogleConsumerConsts.ServiceDescription, mConsumerTokenManager);
// var accessToken = GetAccessTokenForUser();
var accessToken = String.Empty;
// Retrieve the user's profile information
var endpoint = GoogleConsumerConsts.GetGmailFeedsEndpoint;// new MessageReceivingEndpoint("http://api.linkedin.com/v1/people/~", HttpDeliveryMethods.GetRequest);
var request = google.PrepareAuthorizedRequest(endpoint, accessToken);
var response = request.GetResponse();
return (new StreamReader(response.GetResponseStream())).ReadToEnd();
}
No, you don't need to use OpenID if you just want to access the user's Gmail. OpenID is for when you want to authenticate the user. OAuth is for when you want to access the user's data.
You need to include the scope parameter in your authorization request as described in this question: Adding scopes to OAuth 1.0 authorization request with DotNetOpenAuth.

Categories

Resources