Acquire token silently using ADAL JS - azure-active-directory

I have already established session with Azure AD through Open ID Connect, how do I acquire token silently from the browser, I mean without browser redirect, is it possible using ADAL JS?

it is possible. If you are using Angular, all you need to do is specifying the resource you want to target at init time, in the endpoints structure - see https://azure.microsoft.com/en-us/documentation/samples/active-directory-angularjs-singlepageapp-dotnet-webapi/.
If you aren't using Angular, you can use the lower level functions available in adal.js. In particular, see AuthenticationContext.prototype.acquireToken in https://github.com/AzureAD/azure-activedirectory-library-for-js/blob/master/lib/adal.js

Related

Changing AAD accessTokenAcceptedVersion does not result in token version change

I created a new app registration for an app service resource and the accessTokenAcceptedVersion was set to 2 by default (or may be due to my choices). Some clients got an access token for this resource and is being potentially cached on that client.
Later I changed the accessTokenAcceptedVersion to null (i.e. default 1). Now those clients fail to authenticate to the resource (rightfully so) given they have a cached v2 token.
The client in this case is an azure function using the AzureServiceTokenProvider library for getting & caching tokens. So I tried various ways to invalidate the cache involving :
Restarting the function
Waiting out for 1 day (the token expiration time)
Making changes to the app registration
Unfortunately Revoke-AzureADUserAllRefreshToken doesn't seem to work for managed identities.
But I'm still getting a V2 token. What can be done to invalidate this cache or to force a V1 token somehow? I'm trying to do this without any code change currently. But can deploy a change if needed at all.
On other machines/infra I'm able to get a V1 token for the same resource using the different identity. As per my understanding, the token version purely only depends on accessTokenAcceptedVersion. Nothing else.
Please check below points:
If you have changed the accessTokenAcceptedVersion to ‘null’ value, it may also permit v2.0 tokens – It is an issue on AAD’s side. It also depends on the way the app is registered. The difference is that:
If it was done using Azure Portal, then the 'accessTokenAcceptedVersion' field of manifest is set to 'null'
If it was done in the App Registration portal(https://apps.dev.microsoft.com), then it may point to version ‘2.0’
Also check :
The v1 authorization endpoint : https://login.microsoftonline.com/tenantid/oauth2/authorize?
The v1 token endpoint : https://login.microsoftonline.com/tenantid/oauth2/token
Try to change the authority and instance to v1 endpoint in the code and also wherever it is used in the code.
See Microsoft identity platform access tokens - Microsoft identity platform | Microsoft Docs
Both v1 and v2.0 endpoints have their own parameters separately. The v2.0 endpoint expect the ‘scope’ parameter in the request, whereas v1 endpoint expect ‘resource’. So do check the scopes for the api you are referring to and change the code accordingly.
If you still get v2.0 tokens, you must clear the cache of the client application calling your API otherwise until the token has expired, token would be taken from the cache, and would still be a v2.0 token. For that, you may try to call AcquireTokenSilentAsync (in the client while calling you Web API) to force the refresh.
Reference:
Wrong version of access token (got Azure AD V1 instead of V2) GitHub

How to retrieve access tokens without AdalJS?

I registered an application in Azure AD.
How can I get access tokens Programmatically without using AdalJS library in JavaScript?
Thank you!
You would have to use the implicit grant flow manually.
You can see some basic documentation here: https://learn.microsoft.com/en-us/azure/active-directory/develop/active-directory-authentication-scenarios#single-page-application-spa.
You'd authenticate the user by redirecting them to sign in, for example https://login.microsoftonline.com/yourtenant.onmicrosoft.com/oauth2/authorize?client_id=your-client-id&response_type=id_token&redirect_uri=https%3A%2F%2Flocalhost&nonce=abcdef.
Of course you'll need to replace values with your corresponding values.
And generate a unique nonce for each request.
Once the user comes back, you'll need to grab the id_token from the fragment and decode it to get the user info.
Then you can acquire access tokens for APIs with a hidden iframe with a very similar URL as before, but this time with response_type=token&prompt=none&resource=https%3A%2F%2Fgraph.microsoft.com%2F.
Replace the resource with the resource URI/id that you want a token for.
Then you will have to listen for the URL change of the iframe and grab the access token from its fragment when it returns successfully (or parse the error in case authentication fails).
ADAL.JS hides a lot of this complexity from you so I'd strongly advise using it if possible.
It didn't work for me, so I use ADAL. I added script on my page using ScriptLink custom action and acquire token there. WHen adal adds iFrame with the link, I redirect there and it navigates me back to my page with parameters in hash (url), so my script retrieves token from urls hash.

Scope for multiple web apis

I have 2 web apis (A and B) on my b2c. Each one of them publishes their own permissions respectively (scopeA1, scopeA2) and (scopeB1, scopeB2).
On my web application (which already configured and have granted access permission on both apis and the 4 scopes), in order to get authorization code for both apis during authentication, I tried to set my OpenIdConnectAuthenticationOptionsin scope property to include the 4 scopes.
I got an error AADB2C90146: The scope 'scopeA1 scopeA2 scopeB1 scopeB2 openid offline_access' provided in request specifies more than one resource for an access token, which is not supported.
While if I specify only scopes for web api A or B, then it works as per this link
How can I get my web app to use both web apis even with granted permissions for both
Thanks for help
If the two web APIs are separate applications in Azure AD, then you need to request access tokens separately for them.
I'm not familiar with the sample you used as a starting point, but it looks like these lines are where you need to make your change:
// Retrieve the token using the provided scopes
ConfidentialClientApplication app = new ConfidentialClientApplication(authority, Startup.ClientId,
Startup.RedirectUri, credential,
new NaiveSessionCache(userObjectID, this.HttpContext));
AuthenticationResult result = await app.AcquireTokenSilentAsync(scope);
accessToken = result.Token;
You should create an app instance for each of your APIs, and acquire a token for each of them. Then, when you call the APIs somewhere else, use the correct access token in the Bearer authentication header.
I had the same issue and asked a similar question Extend MSAL to support multiple Web APIs
but i have not had an answer, basically to get around it in the short term i have made both my API's use the same authorization client ID + secret and therefore I can reuse the same scopes accross my APIS
its not what i want but if you want to use Azure AD B2C you need to get used to compromising for a while until the support is there
-- I would also say you are using an older version of MSAL which i am also using, im waiting until the version 1 release before upgrading again.
The github talks about using this format
https://github.com/AzureAD/microsoft-authentication-library-for-dotnet
Step 1: Add MSAL to your Solution/Project
Right click on your project > Manage packages.
Select include prerelease > search msal.
Select the Microsoft.Identity.Client package > install.
Step 2: Instantiate MSAL and Acquire a Token
Create a new PublicClientApplication instance. Make sure to fill in your
app/client id
PublicClientApplication myApp = new PublicClientApplication(CLIENT_ID);
Acquire a token
AuthenticationResult authenticationResult = await
myApp.AcquireTokenAsync(SCOPES).ConfigureAwait(false);
Step 3: Use the token!
The access token can now be used in an HTTP Bearer request.

How to Secure an API Call made from a mobile application without username/password?

I have bought an API that can be used in a mobile application. API includes the Key and username as expected.
Within the app, this API needs to be called on Payment confirmation.
I found that using tools like Fiddler, one can see the request made by the application. If that is the case, it is just a matter of seconds to fully get access to the API signature.
It would be of great help if someone can help out/add to this issue.
My thoughts:
Use a server to make this API call instead of calling it directly
from the application.
If a server is used, the issue would still exist as the API call made to the server(eventually which calls the bought API) can also be interrupted/accessed
How to secure the call made to the server from the application?
Technologies: Angular JS, Node JS, Ionic framework
Look at my answer to this question. Instead of using the user name and password, your backend could provide an additional resource that allows the user to create a token with a special scope.
In your AngularJS application you can use the $http or $resource services (if the ngResource module is included) and obtain such kind of token that allows you to access only the parts of your backend your client really needs.
This token must be cached at the client side and included in the header of each request.
In AngularJS storing the token in the header of each request can be done at a central place if you are using the config function of the module you created.
app.config(function($httpProvider) { $httpProvider.defaults.xsrfCookieName = "TOKEN" }
AngularJS also provides some additional security features. For example you could use the JSON vulnerability protection mechanism. If you are using this, your backend had to add the characters )]}', (you could also override the default characters) to each JSON response body.
For other clients the JSON response will be invalid Javascript code, but in your AngularJS application the characters will be automatically removed.
UPDATE
The best way for implementing security for your application would be reading and understanding the OAuth2 specification.
In this video from minute 11:36 to 17:26 the JavaScript flow is described.
This site provides some implementation of the standard for different programming languages.
Some of the aspects in this standard are that all clients and redirect urls must be registered in an additional authentication server. Client are identified by a unique client id.
To avoid that some other application intercepts your requests for extracting the token, the original token should only be active for a small amount of time and each api request must be SSL encrypted.
For providing Single sign-on also refresh tokens can be used.

How to store an auth token in an Angular app

I have an Angular application (SPA) that communicates with a REST API server and I'm interested in finding out the best method to store an access token that is returned from an API server so that the Angular client can use it to authenticate future requests to the API. For security reasons, I would like to store it as a browser session variable so that the token is not persisted after the browser is closed.
I'm implementing a slightly customized version of OAuth 2.0 using the Resource Owner Password grant. The Angular application provides a form for the user to enter their username and password. These credentials are then sent to the API in exchange for an access token which must then be sent as a header (Authorization: Bearer %Token%) for all outbound requests to the API so that it can authorize requests to other routes.
I'm fairly new to the realm of Angular, but the workflow I would like to implement as far as handling these tokens is summarized as follows.
1) The client makes a request to the API providing it with user credentials.
2) If this request is successful, the token is stored somewhere (where is the question)
3) Intercept HTTP requests. If token is set, pass it along as a header to API
4) Token is destroyed when the browser/tab is closed.
I know Angular offers $window.sessionStorage, which appears to be what I am looking for, but I am concerned by the potential for it not to work on all browsers according to various resources I've read. This is an enterprise grade application and must be compatible across a broad range of browsers (IE, Chrome, Firefox). Can I safely use this with the confidence that it will be stable?
The alternatives, from what I understand, are either $window.localStorage or cookies ($cookies, $cookieStore). This would not be an ideal solution for me since I don't want this data to persist, but if this is more reliable I'll have to sacrifice efficiency for compatibility. I was also thinking it might be possible to simply set it as a value on the $rootScope and reference it this way, but I'm not sure if this is feasible.
I hope that all made sense. Any help / suggestions would be greatly appreciated.
Thanks!
If you are looking for something that will definitely not persist then I would simply keep the token in memory and not rely on the browser for storage. However storing inside rootScope would not be best practice.
I would recommend that you wrap your server access code in an Angular Service if you have not done so already. You can then encapsulate your token within that Service at runtime (e.g. as a property) without worrying about having to access it when calling from other parts of your application.
Angular Services are singleton so your "server service" will be a global instance that can be accessed using normal dependency injection.
$window.sessionStorage is the way to go unless you're targeting very old browsers.
According to www.w3schools.com sessionStorage is supported from IE 8.0, Chrome 4.0, Firefox 3.5, and Safari 4.0.

Resources