Web api token based authentication:- Failed to decode token from base64 string to get user name and password - authentication

I am using Web Api Token Based Authentication using OWIN Middleware; the token is generated successfully but i can't decode it; e.g. i cannot extract user name and password from it;
Here is my configuration
my start up code
var oAuthAuthorizationServerOptions = new OAuthAuthorizationServerOptions
{
AllowInsecureHttp = true,
TokenEndpointPath = new PathString("/api/token"),
AccessTokenExpireTimeSpan = TimeSpan.FromDays(1),
Provider = new SimpleAuthorizationServerProvider()
};
// Token Generation
app.UseOAuthAuthorizationServer(oAuthAuthorizationServerOptions);
app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions());
my code that is ued to send the token is
static async Task RunAsync(JObject token)
{
using (var client = new HttpClient())
{
client.Timeout = new TimeSpan(1000000000000);
client.BaseAddress = new Uri("http://localhost/SampleApp/");
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(token["token_type"].ToString(),
token["access_token"].ToString());
}}
my authetication code
var authenticationSchema = httpContext.Request.Headers["Authorization"];
if (!String.IsNullOrWhiteSpace(authenticationSchema))
authentication = AuthenticationHeaderValue.Parse(authenticationSchema);
if (authentication != null)
{
var unencoded = Convert.FromBase64String(authentication.Parameter);
var userpw = Encoding.GetEncoding("iso-8859- 1").GetString(unencoded);
var creds = userpw.Split(':');
return new Tuple<string, string>(creds[0], creds[1]);
}
and the code failed when trying to decode the code from base64 string
note:- my sample token is
3K8vHKHA2ZsKfKbvzUbo4a2sat2JLzvvyxCZ0KSD6s1wUS3t3oDPXuQ89aTmGpsG4ZL8O0cr8M9EUeZGtdM6FBwR7gLFcLZkTaimFGKyyZMNce9trQavVTzs6gam6qach1rPTLv_gIYGgPmM-401PZsr89BIXw4acTpJL3KbXs8y7PQ-o-eTV2IA8euCVkqC02iEnAzmS0SwhBouISCC-HvcNpE2aNixg4JXEt8EslU
you can see the attached for the exception

As far as I can see from the code, access token is sent plain to server; but you need to encode the access token on the client side like:
client.DefaultRequestHeaders.Authorization =
new AuthenticationHeaderValue(token["token_type"].ToString(),
Convert.ToBase64String(Encoding.GetEncoding("iso-8859-1").GetBytes(token["access_token"].ToString())));
Then you can convert access token from base64 string on the server side. The access token string value you provided is not a valid Base64 string, so as expressed in the exception message.

Related

Getting an OAuth2 authentication token in VB.net

I'm trying to get an OAuth token using a ClientID and SecretID.
My code so far:
Dim clientId As String = "8cd6b80dd822961f362"
Dim clientSecret As String = "5afbd4bb280f29cba5ec1f362"
Dim credentials = String.Format("{0}:{1}", clientId, clientSecret)
Dim headerValue = Convert.ToBase64String(Encoding.UTF8.GetBytes(credentials))
Dim content = New FormUrlEncodedContent(New Dictionary(Of String, String) From {
{"client_id", clientId},
{"client_secret", clientSecret},
{"response_type", "code"},
{"redirect_uri", "https://somesite.com/"},
{"grant_type", "authorization_code"}})
Dim requestMessage = New HttpRequestMessage(HttpMethod.Post, "https://api.site.com/oauth2/authorize")
requestMessage.Headers.Authorization = New AuthenticationHeaderValue("Basic", headerValue)
requestMessage.Content = content
Dim client As HttpClient = New HttpClient()
Dim task = client.SendAsync(requestMessage)
Dim response = task.Result
response.EnsureSuccessStatusCode()
Dim responseBody As String = response.Content.ReadAsStringAsync().Result
MsgBox(responseBody)
The above code returns the HTML for the redirect_uri site and not a token.
What am I missing or doing wrong?
Using Postman and the credentials provided I managed to get the token.
The second step of a code flow uses the token endpoint, not the authorize endpoint. Your payload looks correct though. Try posting it to this endpoint:
https://api.site.com/oauth2/token
By default HttpClient is using AllowAutoRedirect = true. The documentation says:
The Authorization header is cleared on auto-redirects and the handler automatically tries to re-authenticate to the redirected location. No other headers are cleared. In practice, this means that an application can't put custom authentication information into the Authorization header if it is possible to encounter redirection.
So depending on the setup of the server you might have to create a CookieContainer and do the redirecting on your own.
Update:
The usage of a certificate store is something I didn't get from your question. If you want to do similar handling of certificates like browsers do you have to implement this feature yourself. Here is a C# example of how you can extend WebClient class with a dedicated CookieContainer and X509 certificate handling. I used it with smart card reader. It should work similar in vb.net. Hope it helps to find the right .Net classes and how to put things together:
public class SmartCardClient : WebClient
{
public CookieContainer Cookies = new CookieContainer();
public Uri LastResponseUri = null;
public X509Certificate2 cert = null;
private string IssuerName = null;
public SmartCardClient(string issuerName)
{
IssuerName = issuerName;
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
SelectCertificate();
}
protected override WebRequest GetWebRequest(Uri uri)
{
var request = base.GetWebRequest(uri) as HttpWebRequest;
LastResponseUri = null;
if (request != null)
{
request.CookieContainer = Cookies;
request.UseDefaultCredentials = true;
request.AllowAutoRedirect = true;
}
return request;
}
protected override WebResponse GetWebResponse(WebRequest request)
{
WebResponse response = base.GetWebResponse(request);
LastResponseUri = response.ResponseUri;
return response;
}
public void SelectCertificate()
{
var store = new X509Store(StoreName.My, StoreLocation.CurrentUser);
store.Open(OpenFlags.ReadOnly | OpenFlags.OpenExistingOnly);
X509Certificate2Collection certs = (X509Certificate2Collection)store.Certificates
.Find(X509FindType.FindByTimeValid, DateTime.Now, false)
.Find(X509FindType.FindByKeyUsage, X509KeyUsageFlags.DigitalSignature, false)
.Find(X509FindType.FindByIssuerName, IssuerName, false);
if (certs.Count > 1)
certs = X509Certificate2UI.SelectFromCollection(
certs, "Select Certificate", "Please select a certificate:",
X509SelectionFlag.MultiSelection
);
if (certs.Count > 0)
cert = certs[0];
store.Close();
}
}

LinkedIn API 403(Forbidden) on any request url including v2

in ASP.NET MVC app I'm trying to use LinkedIn for user Authentication and get the user's full profile.
I'm usin OpenAuth (DotNetOpenAuth and Microsoft.AspNet.Membership.OpenAuth)
Request for User Data
private const string UserInfoEndpoint = "https://api.linkedin.com/v1/people/~" + Fields;
var uri = BuildUri(UserInfoEndpoint, new NameValueCollection { { "oauth2_access_token", accessToken } });
var webRequest = (HttpWebRequest)WebRequest.Create(uri);
using (var webResponse = webRequest.GetResponse())
using (var stream = webResponse.GetResponseStream())
{
if (stream == null)
return null;
using (var textReader = new StreamReader(stream))
{
var xml = textReader.ReadToEnd();
var extraData = XElement.Parse(xml)
.Elements()
.ToDictionary(
el => el.Name.LocalName,
el => el.Value
);
extraData.Add("accesstoken", accessToken);
return extraData;
}
}
This making a successful get of user basic data. but when I change the url like below then it returning 403 Forbidden
private const string UserInfoEndpoint = "https://api.linkedin.com/v2/people/~" + Fields;
or
private const string UserInfoEndpoint = "https://api.linkedin.com/v2/me/?";
I noticed about partnership program, Is that what I need to access these url's? or what is really wrong here?
This docs about the v2 API but nothing about partnership program
if you are using V1 ( till 1st march ) then this is valid :
https://api.linkedin.com/v1/people/~
This url is related to r_basicprofile
if you are moving to V2 then you can't use this url because in V2 you have to take permission from linked to use r_basicprofile
in V2 you can use : r_liteprofile for firstName,lastName,profilePicture,id
r_emailaddress for getting emailAddress
Check this : https://learn.microsoft.com/en-us/linkedin/consumer/integrations/self-serve/migration-faq?context=linkedin/consumer/context

How to access and use Delegated Adal token

The reason there is no info on this is probably because it should be obvious, but I am struggling nonetheless.
After I sign in to my AAD-tenant using ADAL in StartUp.Auth.cs Isuccessfully get a token:
private async Task OnAuthorizationCodeReceivedAAD(AuthorizationCodeReceivedNotification notification)
{
var code = notification.Code;
var credential = new ClientCredential(appId, appSecret);
var userObjectId = notification.AuthenticationTicket.Identity.FindFirst("http://schemas.microsoft.com/identity/claims/objectidentifier").Value;
var context = new Microsoft.IdentityModel.Clients.ActiveDirectory.AuthenticationContext("https://login.microsoftonline.com/tenant.onmicrosoft.com/");
var uri = new Uri(HttpContext.Current.Request.Url.GetLeftPart(UriPartial.Path));
var result = await context.AcquireTokenByAuthorizationCodeAsync(code, uri, credential);
}
I can add a breakpoint here and view the token. My question is, how do I now access this token through my code from other classes? for example to call an API. The token needs to be delegated, so Client Credentials are not going to work, which is all I can find docs on.
The AuthenticationContext class will store the the token in the cache by default when we acquire the token using it.
Then we can retrieve the token from cache based on the resource and user using AcquireTokenSilentAsync. This method will acquire the token from cache and renew the token if it is necessary. Here is an example for your reference:
AuthenticationContext authContext = new AuthenticationContext(authority);
ClientCredential credential = new ClientCredential(clientId, secret);
string userObjectID = ClaimsPrincipal.Current.FindFirst("http://schemas.microsoft.com/identity/claims/objectidentifier").Value;
AuthenticationResult result = await authContext.AcquireTokenSilentAsync(resource,credential, new UserIdentifier(userObjectID, UserIdentifierType.UniqueId));

How do I authenticate OneDrive for Business with Service to Service oauth2 authentication?

The tutorial for OneDrive for Business (here: https://dev.onedrive.com/auth/aad_oauth.htm)
However, I don't want the user to have to login as I'm building a web API - I want the app to login. So, I have followed the tutorial for service to service authentication (here: https://msdn.microsoft.com/en-us/library/azure/dn645543.aspx) which gets me an access token.
However, when I try to authenticate with the service I get an error saying "unsupported app only token". The code I'm using is below (btw, I'm using RestSharp):
public string GetAccessToken()
{
var client = new RestClient("https://login.microsoftonline.com/<tenant>/oauth2");
var request = new RestRequest("token", Method.POST);
request.AddParameter("grant_type", "client_credentials");
request.AddParameter("client_id", <client_id>);
request.AddParameter("client_secret", <client_secert);
request.AddParameter("resource", "https://<tenant>-my.sharepoint.com/");
var response = client.Execute(request);
var content = response.Content;
var authModel = JsonConvert.DeserializeObject<AuthResponseModel>(content);
return authModel.AccessToken;
}
this gets me the access token
This is how I try to access my drive:
public string GetDrive()
{
var accessToken = GetAccessToken();
var client = new RestClient("https://<tenant>-my.sharepoint.com/_api/v2.0/");
var request = new RestRequest("drive", Method.GET);
request.AddHeader("Authorization: Bearer", accessToken);
var response = client.Execute(request);
var content = response.Content;
return content;
}
Does anyone have any tips? This is getting slightly maddening.

How to consume REST service from a MVC 4 web application?

Can someone give me pointers on how to How to consume an external REST service from a MVC 4 web application? The services rely on an initial call with credentials base 64 encoded, then returns a token which is used for further web service queries.
I cannot find an easy primer on how to do this kind of thing, could someone help please?
I have all this working in classic ASP & JQuery but need to move over to an MVC 4 web application.
You could use the HttpClient class. Here's an example of how you could send a GET request and use Basic Authentication:
var client = new HttpClient();
client.BaseAddress = new Uri("http://foo.com");
var buffer = Encoding.ASCII.GetBytes("john:secret");
var authHeader = new AuthenticationHeaderValue("Basic", Convert.ToBase64String(buffer));
client.DefaultRequestHeaders.Authorization = authHeader;
var response = client.GetAsync("/api/authenticate").Result;
if (response.IsSuccessStatusCode)
{
string responseBody = response.Content.ReadAsStringAsync().Result;
}
Once you have retrieved the access token you could make authenticated calls:
var client = new HttpClient();
client.BaseAddress = new Uri("http://foo.com");
string accessToken = ...
var authHeader = new AuthenticationHeaderValue("Bearar", accessToken);
client.DefaultRequestHeaders.Authorization = authHeader;
var response = client.GetAsync("/api/bar").Result;
if (response.IsSuccessStatusCode)
{
string responseBody = response.Content.ReadAsStringAsync().Result;
}