401 When passing the token using graphic onenote api - azure-active-directory

I am new to Microsoft graph so this might be a dumb question.
So I am writing a command line application trying to update a page in our team onenote. (enterprise onenote)
Here is the code I got work getting the token.
https://login.microsoftonline.com/common/oauth2/authorize?client_id=my_client_Id&response_type=code&redirect_uri=Some_uri&resource=https://graph.microsoft.com&scope=Notes.ReadWrite.All
I got the token as strCode and trying to retrieve all the notes under this account by these codes:
var baseAddress = new Uri("https://graph.microsoft.com/v1.0/me/onenote");
using (var httpClient = new HttpClient { BaseAddress = baseAddress })
{
var request = new HttpRequestMessage(HttpMethod.Get, #"/pages");
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", strCode);
using (var response = httpClient.SendAsync(request).Result)
{
string responseData = response.Content.ReadAsStringAsync().Result;
}
}
And in the response data I got
"{ \"error\": { \"code\": \"InvalidAuthenticationToken\", \"message\": \"CompactToken parsing failed with error code: -2147184105\", \"innerError\": { \"request-id\": \"*********************", \"date\": \"2017-06-08T18:25:06\" } } }"
Any idea how to fix this..?

Problem resolved .
I need to convert the authentication code into a "real" access token..
The one that I got is not an access token.

Related

How to get access token in typed HttpClient

I've got a IdentityServer4/WebAPI setup and a typed HttpClient in my server-side Blazor application. I want to add the access token dynamically when a request to the API is made. But neither the HttpContext nor the AuthenticationStateProvider is accessible in the AddHttpClient method or in the AddHttpMessageHandler.
This works locally but running on the server httpContextAccessor is null:
services.AddHttpClient<IMyClient, MyClient>((serviceProvider, client) =>
{
var httpContextAccessor = serviceProvider.GetService<IHttpContextAccessor>();
var accessToken = await httpContextAccessor.HttpContext.GetTokenAsync("access_token");
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);
}).AddHttpMessageHandler<MyApiBearerTokenHandler>();
Trying to access the AuthenticationStateProvider
services.AddHttpClient<IMyClient, MyClient>((serviceProvider, client) =>
{
var authStateProvider = serviceProvider.GetService<AuthenticationStateProvider>();
}).AddHttpMessageHandler<MyApiBearerTokenHandler>();
throws the following error:
'Cannot resolve scoped service
'Microsoft.AspNetCore.Components.Authorization.AuthenticationStateProvider'
from root provider.'
How do I get the access token into AddHttpClient? Am I completely on the wrong track?

Azure B2C - 401 unauthorised trying to read id_token in code after logging in

I am trying to use the token granted by a secured AAD domain when using my web app
I followed the advice on this link: Retrieve Access Token within a AAD secured Azure Web App
I have managed to get as far as logging in and verifying the ./me URL correctly shows me my token
However when I try and call same token in code I get 401 unauthorised
I have been using the Resource Explorer to configure the additionalLoginParams and have tried to put the app ID as well as the graph URL but nothing has solved the problem
async public Task<string> GetToken()
{
HttpClient _client = new HttpClient();
string _token = "";
HttpResponseMessage response = await _client.GetAsync("https://alfreton.azurewebsites.net/.auth/me");
response.EnsureSuccessStatusCode();
string responseBody = await response.Content.ReadAsStringAsync();
ReadUserToken readUserToken = new ReadUserToken();
readUserToken = JsonConvert.DeserializeObject<ReadUserToken>(responseBody);
_token = readUserToken.id_token;
return _token;
}
}
}
EDIT Following the advice below the code now looks like this but I am still getting an Unauthorized error messsage
async public Task<string> GetToken()
{
HttpClient _client = new HttpClient();
string _token = "";
string accessToken = this.Request.Headers["X-MS-TOKEN-AAD-ACCESS-TOKEN"];
_client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);
HttpResponseMessage response = await _client.GetAsync("https://alfreton.azurewebsites.net/.auth/me");
response.EnsureSuccessStatusCode();
string responseBody = await response.Content.ReadAsStringAsync();
ReadUserToken readUserToken = new ReadUserToken();
readUserToken = JsonConvert.DeserializeObject<ReadUserToken>(responseBody);
_token = readUserToken.id_token;
return _token;
}
When I read through the headers, I find there is X-MS-TOKEN-AAD-ID-TOKEN - can I use that to get an access token?
I agree with #juunas, the URL expects the authentication cookie to be passed in the request when you aceess ./me URL.
The provider-specific tokens are injected into the request header, so you can easily access them. Your provider is AAD, so it should be
string accessToken = this.Request.Headers["X-MS-TOKEN-AAD-ACCESS-TOKEN"];
OK I figured it out, what I needed to do is get X-MS-TOKEN-AAD-ID-TOKEN from the Request Headers after logging in then pass that in as the Bearer and that in turn got me a X-MS-TOKEN-AAD-ACCESS-TOKEN which I can use for accessing the API
Thanks loads!

Microsoft graph API: getting 403 while trying to read user groups

I am trying to get user's group information who log-Ins into the application.
Using below code, when I am hitting https://graph.microsoft.com/v1.0/users/{user}, then I am able to see that user is exist (200), but when trying to hit https://graph.microsoft.com/v1.0/users/{user}/memberOf, then I am getting 403.
private static async Task Test()
{
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", "TOKEN HERE");
var user = "testuser#onmicrosoft.com";
var userExist = await DoesUserExistsAsync(client, user);
Console.WriteLine($"Does user exists? {userExist}");
if (userExist)
{
var groups = await GetUserGroupsAsync(client, user);
foreach (var g in groups)
{
Console.WriteLine($"Group: {g}");
}
}
}
}
private static async Task<bool> DoesUserExistsAsync(HttpClient client, string user)
{
var payload = await client.GetStringAsync($"https://graph.microsoft.com/v1.0/users/{user}");
return true;
}
private static async Task<string[]> GetUserGroupsAsync(HttpClient client, string user)
{
var payload = await client.GetStringAsync($"https://graph.microsoft.com/v1.0/users/{user}/memberOf");
var obj = JsonConvert.DeserializeObject<JObject>(payload);
var groupDescription = from g in obj["value"]
select g["displayName"].Value<string>();
return groupDescription.ToArray();
}
Is this something related to permission issue, my token has below scope now,
Note - Over here I am not trying to access other user/group information, only who log-ins. Thanks!
Calling /v1.0/users/[a user]/memberOf requires your access token to have either Directory.Read.All, Directory.ReadWrite.All or Directory.AccessAsUser.All and this is
documented at https://developer.microsoft.com/en-us/graph/docs/api-reference/v1.0/api/user_list_memberof.
A great way to test this API call before implementing it in code is to use the Microsoft Graph explorer where you can change which permissions your token has by using the "modify permissions" dialog.

Json Web Token - jose4j - SyntaxError: Unexpected token e in JSON at position 0

I have a controller which tries to get a token.
I got this error in postman when I execute it in the view PRETTY
Unexpected 'e'
But if I go to the view RAW I can see the token like this.
eyJraWQiOiIxIiwiYWxnIjoiUlMyNTYifQ.eyJpc3MiOiJJc3N1ZXIiLCJhdWQiOiJBdWRpZW5jZSIsImV4cCI6MTQ3NTQ1OTMyNiwianRpIjoiTmF3d000bDVGRmFRZ0dBQkwzS3N5USIsImlhdCI6MTQ3NTQ1ODcyNiwibmJmIjoxNDc1NDU4NjA2LCJzdWIiOiJzdWJqZWN0IiwiZW1haWwiOiJtYWlsQGV4YW1wbGUuY29tIn0.f97SFDaAjUyUDK_UQgwgnCTewd0yw6tWK6DFLzpALFq177f1QMTYPbVdiIG1ViJ0FNJ6fUCleCd8BmrToUn25VSmRv799dtcz-xaN1kOgw90NQ00kPUhnDXG01-7hImkHfbmZZWORukP2yPK1sHWzpdjg9fJOvRZpZ6ZWli4HeuYRJqsFOv7PvwmGH9JnfRTf_2tboL-oAYBpT367eh60TggrvMgmrO_Taj5M7qGG0GpbwuVh_HTAkaKv7T2WmuZ2JPANhe5JvY_DDaqChtwd0IPREAhK3Xr-nTOIuwbQ0Y1hhOGfvDmikQj6DXnCERYixP6eR1dhC8n3bKvXyaVmA
This is the code of my controller.
#Path("/demo")
#GET
#Produces(MediaType.APPLICATION_JSON)
public Response testMethod() throws JSONException, IOException {
RsaJsonWebKey rsaJsonWebKey = RsaJwkGenerator.generateJwk(2048);
rsaJsonWebKey.setKeyId("k1");
JwtClaims claims = new JwtClaims();
claims.setIssuer("Issuer");
claims.setAudience("Audience");
claims.setExpirationTimeMinutesInTheFuture(10);
claims.setGeneratedJwtId();
claims.setIssuedAtToNow();
claims.setNotBeforeMinutesInThePast(2);
claims.setSubject("subject");
claims.setClaim("email","mail#example.com");
JsonWebSignature jws = new JsonWebSignature();
jws.setPayload(claims.toJson());
jws.setKey(rsaJsonWebKey.getPrivateKey());
jws.setKeyIdHeaderValue(rsaJsonWebKey.getKeyId());
jws.setAlgorithmHeaderValue(AlgorithmIdentifiers.RSA_USING_SHA256);
String jwt = jws.getCompactSerialization();
if(jwt == null){
return Response.status(204).entity(jwt).build();
}
return Response.status(200).entity(jwt).build();
}
I ignore the error in postman but I get the same error when try to execute it in Chrome.
I try to call my RESTful controller with angular like this, but I always get into the onError method with the message within the response parameter.
angular.min.js:118 SyntaxError: Unexpected token e in JSON at position 0
This is the code in angular
app.service('TokenService', function($http){
this.getToken = function(){
function onSuccess(response){
console.log('got it');
}
function onError(response){
console.log('fail');
}
return $http({
method : 'GET',
url : 'http:localhost:8080/rest/demo',
header: {'Content-Type' : 'application/json'}
}).then(onSuccess, onError);
}
}
My reference of the code for the token is from here with Jose4j
UPDATE
I solved this. I still think the way I did it initially it should work also, but I don't still understand why I get the error.
I created a pojo named Token with a property token as String then I changed this
return Response.status(200).entity(jwt).build();
to this:
Token token = new Token();
token.setToken(jwt);
return Response.status(200).entity(token).build();
This is my workaround to return a real json object.
I know it's much too late now, but I've faced the same problem and got it fixed with your solution, so Thanks.
Just for the sake of whoever came across this issue later. In my case I do it like this.
HashMap<String, String> credential = new HashMap<>();
credential.put("token", jwtToken);
apiResp = ResponseEntity.ok(jwtToken);
Btw, I also seem to figured out the problem which is Angular might expect that response from server is JSON object by default then parse it to JavaScript object for us.
So we got our error because we return string as a response entity and it can't parse string to an object. That's why putting the token in POJO solved it.
The other way around is setting return type from client-side like this.
login(username: string, password: string): Observable<any> {
let body = {username, password};
let res = this.http.post(
`${API.AUTHENTICATION}`, body, {
responseType: 'text'
});
return res;
}
Now, JS will know that the response is of string type and it won't try to parse it to an object anymore.

Can't get content-disposition from http.get header?

I am trying to download a file using web API + Angularjs and it's working fine, however I'm sending 'content-disposition' in the header from the web API but I'm unable to access it in the response-header.
WebAPI:
[HttpGet]
[AllowCrossSiteJson]
public HttpResponseMessage GetAcquisitionsTemplate()
{
var docContent = _d.FirstOrDefault();
Stream stream = new MemoryStream(docContent.Content);
HttpResponseMessage result = new HttpResponseMessage(HttpStatusCode.OK);
string contentDisposition = string.Concat("attachment; filename=", docContent.Name.Replace(" ", String.Empty), "." + docContent.Extension);
result.Content = new StreamContent(stream);
result.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
result.Content.Headers.ContentDisposition = ContentDispositionHeaderValue.Parse(contentDisposition);
return result;
}
Client Side (AngularJs):
$http.get(url)success(function (data, status, headers) {
var header= headers();
})
In the header I'm getting the following values but I'm unable to get content-disposition. Please correct me where I'm wrong?
I guess you are trying to hit it from localhost while the file is hosted on the server, in that case ask your server team to allow , Access-Control-Expose-Headers(‘Content-Disposition’) . With this Header, custom headers like COntent-Disposition will be accessible to you over cross domain

Resources