Getting "invalid_token" when accessing Web API with ADAL.js - azure-active-directory

I followed the ideas in this post. I just made a few changes, like using ASP.net core and Angular 2 front running on the same port using jwt bearer token authentication.
I'm using ADAL.js to authenticate Azure AD and this process seems to work fine. I'm getting my token from Azure AD and its getting save in localstorage.
When I use the token which is getting save in local storage to call my API I'm getting 401
Call from Angular 2 to WebApi both residing on same port.
var token = localStorage["adal.access.token.keye1b88e53-810a-474d-93af-bb98c956d01e"];
console.log(token);
let headers = new Headers({
'Authorization': 'Bearer ' + token, 'Accept': 'application/json; odata.metadata=minimal'
});
let options = new RequestOptions({ headers: headers });
return this.http.get('https://localhost:44375/api/values', options)
.map((response: Response) => response.json()).subscribe((val) => {
console.log(val);});
This call comes back with a 401 with this message
Bearer error="invalid_token", error_description="The token is expired"
Any ideas are appreciated. Thanks!

By default, the token we acquired will be expired in an hour. According your error message, your token should have been expired, each token will have a expiration timestamp, you can check the key adal.expiration.key1b88e53-810a-474d-93af-bb98c956d01e in your localstorage for the expired time.
Actually, if you are using adal-angular module in your application, as the description on its Github repository:
Any service invocation code you might have will remain unchanged. Adal's interceptor will automatically add tokens for every outgoing call.
We don't need to manually set the Authorization header in the outcall requests. Also, if you consist, you can try to use:
config.headers['Authorization'] = 'Bearer ' + localStorage.getItem("adal.idtoken");
And renew your token manually.
Additionally, you can check all the key/value in local storage created by adal.js:

On the Web API end I changed
app.UseJwtBearerAuthentication(new JwtBearerOptions
{
Authority = Configuration["Authentication:AzureAd:AADInstance"] + Configuration["Authentication:AzureAd:TenantId"],
Audience = Configuration["Authentication:AzureAd:Audience"]
});
to
app.UseJwtBearerAuthentication(new JwtBearerOptions {
Authority = Configuration["Authentication:AzureAd:AADInstance"] + Configuration["Authentication:AzureAd:TenantId"],
Audience = Configuration["Authentication:AzureAd:ClientId"],
TokenValidationParameters = new TokenValidationParameters { SaveSigninToken = true }
});

You can also set the Application id of the AD application to be same in both Web API and also in client application as **clientId** and make sure you enable **"oauth2AllowImplicitFlow": true,** in manifest(available azure portal of the AD).

Related

Azure AD Bearer Token has wrong "aud" claims

I am trying to use AAD delegated permission Bearer tokens for a Visio VSTO addin to create SharePoint Online pages using CSOM. Initially I was able to get this working entering username / password following Modern Authentication with CSOM for Net Standard
However, I would like for the user to select an existing AAD account. When I attempt to use the following code the Bearer token "aud" claim is consistently set to "00000003-0000-0000-c000-000000000000" which is the Graph API. Whilst a ClientContext object is returned I am getting a HTTP 401 Unauthorized error when performing a page lookup.
The code is as follows
//
// Get Client App
//
var ClientApp = (PublicClientApplication)PublicClientApplicationBuilder.Create(<AAD App ID>)
.WithDefaultRedirectUri()
.WithTenantId(<AAD Tenant ID>)
.WithAuthority(AzureCloudInstance.AzurePublic, <AAD Tenant ID>)
.Build();
//
// Prompt for user to select preferred AAD account
// The returned JWT Bearer Token "aud" claim is 00000003-0000-0000-c000-000000000000
//
var Token = ClientApp.AcquireTokenInteractive(scopes)
.WithPrompt(Prompt.SelectAccount)
.WithParentActivityOrWindow(GetActiveWindow())
.ExecuteAsync()
.GetAwaiter()
.GetResult();
//
// Get client Context
//
var ClientContext = AuthenticationManager.GetAzureADAccessTokenAuthenticatedContext(<SharePoint Site URL>, Token.AccessToken);
//
// Using the Client Context to query the Site results in HTTP 401
//
ClientContext.Load(ClientContext.Web, p => p.Title, t => t.Description);
ClientContext.ExecuteQuery();
Looking at the code for the AuthenticationManager class in the above link I can see that the AAD Bearer request is passing the following resource request parameter to the SharePoint online URL:
var body = $"resource={resource}&client_id={clientId}&grant_type=password&username={HttpUtility.UrlEncode(username)}&password={HttpUtility.UrlEncode(password)}";
So it seems that AAD is setting the Bearer token "aud" claim based upon this parameter. However, when I try and add this parameter using 'WithExtraQueryParameters' I am getting the following error: "AADSTS901002: The 'resource' request parameter is not supported"
Ok, I figured out the problem. The scope needs to be prefixed with the resource:
string[] scopes = { "https://<domain>.sharepoint.com/AllSites.Write", "user.read" }
Then retrieve the token
this.Token = await ClientApp.AcquireTokenInteractive(scopes)
.WithPrompt(Prompt.SelectAccount)
.WithParentActivityOrWindow(GetActiveWindow())
.ExecuteAsync();

Authorization token never goes in ReactJS request header using Axios and Backend with Spring Boot Security

This might seem a duplicate but it's not. I have learned a lot the others questions/answers.
I this case I have Spring Boot Security enabled generating a JWT token when user logs in - that's working well.
When the access token is returned I need to make a call to a protected endpoint to get some info from that user.
In the Frontend side I am using ReactJS with Axios, every call works fine unless I try to call a protected endpoint passing the token in the Authorization property on the header.
The odd thing here is that when testing using Postman it works perfectly well:
1) Login with email and password
2) Get returned token and make any call to any protected endpoint
What does Postman do so different from what I am doing that the Authorization on the header never gets sent?
I am using an interceptor to inject the token on the requests when the token exists on the local storage (and it does exist):
export const api = axios.create({
baseURL: ROOT_API
});
api.interceptors.request.use(async config => {
config.headers["Accept"] = "application/json; charset=utf-8";
config.headers["Content-Type"] = "application/json; charset=utf-8";
config.headers["If-Modified-Since"] = "Mon, 26 Jul 1997 05:00:00 GMT";
config.headers["Cache-Control"] = "no-cache";
const token = await getToken();
if (token) {
config.headers.Authorization = `Bearer ${token}`;
}
console.log("config => ", config);
return config;
});
But every call I do I get a 401 status code, because, of course, the token never gets on the API on the server side.
As you can see on the picture that is the header that was supposed to be sent. But when I check on the server side it's always null.
I would appreciate any help on this.

How to avoid catching the HTTP OPTIONS request in the express.js auth middleware

Okay I have a backend API built in express.js that responds to a SPA built in AngularJS. I am using token authentication to verify the access of clients to fetch certain resources.
The way I check on wether the incoming request from the front-end has an Authorization header containing the Bearer token or not is in an authentication middleware I made myself in express.js.
The problem is that AngularJS sends a preflight OPTIONS reuqest before the actual get request and the OPTIONS one is the first thing caught by the middleware causing it to refuse the request since it doesn't have a Bearer token in it and it halts the execution.
The question is how to avoid catching this annoying OPTIONS request in my Authentication middleware and just catch the actual get request which contains a bearer token authorization.
This is the code of the http request sent from my angularJS app
return $http(
{
method: 'GET',
url: API_URL,
headers: {
'Authorization': 'Bearer ' + 'faketoken'
}
}
)
do these packets go to a L3 Ip address? or a L2 protocols?

token authentication on Django REST framework + Angular project

I'm using DRF and Angular, which client environment is a mobile devices.
I've found out a django-rest-auth package.
I haven't hesitate to choice for that, because that provides a TokenAuthentication feature, which is suitable with a mobile client.
When I sent a login request, client receives a token.
Then, I was add a the bellow in request success callback.
login: function(username, password) {
return $http.post('http://192.168.0.3:8000/rest-auth/login/', {
'username':username,
'password':password,
}).success(function(data) {
$http.defaults.headers.common.Authorization = 'Token ' + data.key;
Account.authenticated = true;
console.log("login success", data)
})
At server's console, output about incoming request is the bellow
'HTTP_AUTHORIZATION': 'Token 3fae470d169adb550e538c99a754fcfbe3485f75'
But, I saw an unexpected result, like this:
request.user AnonymousUser
request.auth None
According to here, If I send a request with token, which extra authentication works will be processed by itself.
Should I add an other code for complete authentication?
(ex. register a token into django's session storage.)
I would like to hear your advice.
I solved for a problem, which cause is just stupid mistakes
I didn't look carefully at the reference documents.
To use the TokenAuthentication scheme you'll need to configure the authentication classes to include TokenAuthentication, and additionally include rest_framework.authtoken in your INSTALLED_APPS setting:
So I had added the configuration in settings.py.
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework.authentication.BasicAuthentication',
'rest_framework.authentication.SessionAuthentication',
# I add this config
'rest_framework.authentication.TokenAuthentication',
)
}
After send a login request terminal to server, then If I request with the "GET", terminal console outputs like the below.
request.user admin
request.auth 626ba4b1357cb472fc4bb0c58afb026cf21dd175

Authentication using Angularjs

I am fairly new to AngularJS
I have a resource that I use for user management which is part of a service following this article.
Once sending the login request to the server I am getting a response with a set-cookie as part of the header.
What is the best practice to add this cookie to every request I am sending to the server?
myApp.factory('UserService', ['$resource', function ($resource) {
var userRes = $resource('http://<MyDomain>/api/v1/user/:param',
{param: '#param'},
{
login: {
method: 'POST'
},
logout: {
method: 'DELETE'
}
});
var user;
return {
signIn: function () {
user = userRes.login({param: 'login'}, {"email": "SomeName#MyDomain.com", "password": "test1"});
userRes.get({param: '1'});
},
userRes.login has set-cookie header in on the response
userRes.get does not send the cookie that was just received.
Cheers
Since your API is in a different domain you can't use cookies in this case. We've tried and we failed to put it simple there is no way, not only it doesn't work with CORS but also it doesn't work if you embed an iframe. The iframe trick fails on safaris mostly but it is not reliable.
What we usually do is to return a JWT (Json Web Token) from the API and attach a header then to every API request as Authorization: Bearer JWT.
This JWT can be decoded using a public key from the front end (and it will contain the user profile) and validad with a private key in the backend.
JWT is simple and there are plenty of libraries for every language/technology.
Auth0 is an authentication broker that can validate with any identity provider or custom databases, and it returns JWTs using standars. It provides a clientID that can be used to decode the profile in the front end and a secret to validate the tokens in the backend as well as client side library to do this.
Disclaimer: I work for auth0.

Resources