Azure AD / MSAL.js - is it safe to include the tenantId? - azure-active-directory

Is it safe to include the clientId and tenantId in the msal.js implementation? I believe i read Joonas Westlin say that embedding the ClientId is fine (I can't find the post now).
There is a place for it in the library so it seems that it is ok:
this.msal = new UserAgentApplication(
{
auth: {
clientId: this.clientId,
authority: `https://login.microsoftonline.com/${this.tenantId}`,
redirectUri: Uri + "/login",
},
However one would think such identifying information is to be kept secret.

Short answer: Yes, it's safe to include clientId and tenantId.
Your concern is valid since with JavaScript based applications (like SPA's) any information that you're putting in is potentially exposed to users and can be misused. Although tenantId and clientId aren't such information, client secret or keys would be something sensitive and to be avoided.
tenantId is available publicly anyway as part of the OpenID Discovery document for tenant. You can access it using a URL of this format
https://login.microsoftonline.com/{tenantID or tenantDomain}/v2.0/.well-known/openid-configuration
clientId is an identifier for your app registration. To answer your concern about including it.. clientId alone doesn't establish application's identity, you need to have client secret along with it as well, to be able to use application's identity.
So from a security standpoint any public client application (like a JavaScript based SPA or even a desktop native app) should not make use of client secret, as these applications can not keep it safely and it can get compromised. Secrets can only be handled by confidential clients like server based web application or backend daemon process.
Here is Microsoft guidance for Implicit grant flow which is usually the flow used by JavaScript/SPA apps - Microsoft identity platform and Implicit grant flow
Here is a similar SO post about clientid and tenantId with good explanation - Are the Azure Client Id, Tenant, and Key Vault URI considered secrets?
I couldn't quickly find the post from Joonas Westlin that you mention in question, but Joonas's advice about clientId is correct as usual.

Related

Difference between Oauth in frontend and backend

I can implement Oauth in React-frontend(https://www.npmjs.com/package/react-google-login, input taken is only clientID) as well as SpringBootSecurity-backend(https://github.com/spring-guides/tut-spring-boot-oauth2, input taken is clientID as well as clientSecret). What is the difference between these two ways? More specifically how is the presence and absence of clientSecret affecting these two ways.
Without a client secret, the React frontend (perhaps a SPA: Single Page App) completely relies on the redirect uri that was registered with the auth server to provide some semblance of security. This uri was previously registered with the auth server. However, it is not as secure since the malicious app/user can tap into the communication on the redirect uri. Mobile apps suffer as well in this circumstance. And the client id is available just by inspecting the source in a browser. Therefore the malicious app has all the information to mount an attack and access the token. This is known as OAUTH "implicit" grant type flow. And it leads to token leakage or token replay.
To circumvent this issue, PKCE (Proof Key for Code Exchange) comes into the picture. Details here. Provides information on the reason for its existence in terms of shortcomings of the implicit flow that you document in your question.
The PKCE RFC here also details attack scenarios.
There is also this answer that answers very well on this aspect on this very site.

IdentityServer4 - Understanding flows and Endpoints. How is it related to OAuth and OpenIDConnect?

I am integrating the security aspect of webapplication. I have decided to use OAuth,
so we have a REST WebApi in AspNet Core 3.0, the client which is a SPA created in React, and the Identity Server 4.0 app which is also in AspNet Core 3.0.
I read that OAuth is created for Authorization and not for Authentication.
For Authentication, seems that exists something else called OpenIDConnect, so the first question that comes to my mind, and on which I cannot find an easy answer is: are OAuth, OpenIDConnect and IdentityServer related technology?
Which is the best solution for authentication, considering that I would like to create users in a SqlServer Database, and if it's possible I would like to use Entity Framework for the porpose?
The flow for my authentication would be:
User writes Username and Password, if they are right he receive the JWT Token, without redirecting him/her to the authorization page.
At this point the problem are:
which is the right endpoint to do this flow:
is it the /authorize or the /token endpoint?
I have a lot of confusion for the questions above.
The second thing, what is the best way to retrieve the user informations?
For example if my endpoint needs to understand from the logged in user what are his data, I think that or I retrieve from the endpoint or from the JWT token.
Even here I have no clue on which is the best.
I read that OAuth is created for Authorization and not for Authentication. For Authentication, seems that exists something else called OpenIDConnect, so the first question that comes to my mind, and on which I cannot find an easy answer is: are OAuth, OpenIDConnect and IdentityServer related technology?
That's right. OAuth was the first one introduced and allows the person requesting it access to the resources (its handing out access tokens). OIDC (OpenID Connect) on the other-side extends this concept by an identity, the authentication part.
The identity token verifies the identity of the person to your application. Instead of providing identity via username + password (i.e. user creating an account on your website), they get redirected to your authentication provider/app and enter their login there and you get an identity token in return (and/or an access token, depending on the flow and scopes you request).
The identity token is an JWT token (or reference token). The JWT token contains all of the users identity information required for your application (user id, email, displayname, age, etc.) and is cryptographically signed. Only the Identity Server knows the key used to sign it up and you can verify it with the public key from the OIDC (IdSrv here) provider.
Reference token works similar, but claims are requested on the server side and cached.
With identity token you can not access the users resources. Example: Facebook.
When you sign in your application with an facebook account, most page will only request identity token to verify that its the same user (instead of using a username / password combination). But with that one, the application can't access your facebook posts or do posts in your name.
If the application requests an access token (token scope), then also an access token will be returned (if the application is allowed to via allowed scopes). You will be asked to grant the permissions to the resources which the application requests.
With that token, the application can read your posts or post in your name.
Which is the best solution for authentication, considering that I would like to create users in a SqlServer Database, and if it's possible I would like to use Entity Framework for the porpose?
Doesn't really matter. Either one can be used, all you really need is the "sid" (subject id) claim and associate that one with your user.
Identity Server can issue both, depending on what the client asks (if client asks for id_token response type, it will receive an identity token, if it asks for token an access token. Both can be specified or just one).
At this point the problem are: which is the right endpoint to do this flow: is it the /authorize or the /token endpoint? I have a lot of confusion for the questions above.
/authorize is used to authorize the user (have him login, and send back to your website). Its used for so called interactive flows, where the user enters credentials
/token endpoint you can only retrieve a token (resource owner flow (username + password), client credentials (for machine to machine authentication), refresh token (to get a new access token by using an refresh token (if you asked for offline_access scope, which gives and refresh token)
The second thing, what is the best way to retrieve the user informations?
the /userinfo endpoint, see docs: http://docs.identityserver.io/en/latest/endpoints/userinfo.html
As the doc says to access that, the client needs to request the openid scope.
For example if my endpoint needs to understand from the logged in user what are his data, I think that or I retrieve from the endpoint or from the JWT token.
Yes you can retrieve it from JWT token, if you use JWT token. If you use reference token, its just an ID.
And last but not least the /introspection endpoint can be used to validate the token (if your consuming application has no libraries to decrypt and validate signature of the token.
If you can, its best to use the Identity Server client libraries (i.e. IdentityServer4.AccessTokenValidation package for ASP.NET Core or oidc-client for npm/javascript based applications) which should be picking up the correct endpoints, so you don't have to worry about it

How Do I Call Azure API Management From React?

My front end is using ReactJS and when I was testing locally I was using axios to make the calls. e.g.
axios.defaults.baseURL = process.env.REACT_APP_API_URL;
axios.get('/me').then((resp) => {
this.setState({identity: resp.data});
}).catch(() => {
console.log('Failed to retrieve identity');
});
I have now moved my API behind Azure API Management which is set up to require a subscription to use.
Part of the APIM policy checks the Active Directory group to validate the user is in the right group.
Therefore, I need to add 2 parts to my javascript
authenticate against Active Directory
send the Ocp-Apim-Subscription-Key in the header
react-adal looks like it might handle the login.
However, I can't work out how to modify my existing code to use it and send the header.
Its also not clear whether it is a security risk to hard code the Ocp-Apim-Subscription-Key in the javascript or if it should be retrieved on the fly.
If it should be retrieved on the fly, where should I store it and how should I retrieve it securely?
After you handle the login with react-adal, you can also modify how you send the subscription key to APIM.
APIM lets you define how you want to send the subscription key - custom HTTP header or the query string:
Both fields are text fields with pre-defined values which you can freely change (well keep in mind these are either HTTP header name or query string variable names).
To the question weather you should keep that secret. Well, you subscription key is your secret. And it is not short lived like the access token. So you should keep that as secret as possible and do not just put it in your JS code.
However I am not really convinced that a SPA application should use APIM subscription key to invoke the API. APIM subscription keys are just a symmetric keys used to authentication/authorization. As such (being symmetric keys) using these in a SPA application be would like using your username and password for the database in your SPA app. It doesn't really matter in what stage you put that key in the browser. The moment you put APIM subscription key in the browser, you cannot longer trust that key. Users can modify it, completely remove it, or use another valid subscription key if they find one.
For SPA application I would just use the Azure AD Authentication and shape the authorizations based on the bearer token. I suppose you already perform JWT validation checks in your policy? You can extract any and all claims form the token and you can make authorization decisions based on claim values.
If the React app is hosted in Azure App Service, then you should be able to register the React app with managed identity and use Azure KeyVault to keep the secret.
https://learn.microsoft.com/en-us/azure/key-vault/tutorial-net-create-vault-azure-web-app

Are there security concerns exposing the clientId and tenant in client side code when using adal/adal-angular.js

I'm in the process of implementing AAD single sign on in our application and we will be using the adal.js/adal-angular.js library with our MEAN stack application. Part of initializing the library is to call init() and provide the tenant and clientId
adalProvider.init(
{
tenant: "mycompany.onmicrosoft.com",
clientId: "05bdd8d7-XXXX-XXXX-XXXX-5f2769f8b9b6"
},
$httpProvider
);
for example.
If someone views the source and takes the tenant and clientId can they use that somehow in their own application maliciously?
Does AzureAD check the URL the request came from and block it if it's not the configured login url?
Seems as though the clientId is more like a public key but if the only 2 things needed for an app to trigger authentication with AzureAD is the tenant and clientId and those are exposed client side in source code that someone could use them to create a phishing site X or to grab id_tokens if the request is redirected back to their site X rather than the original site
Does Azure rely on the configured settings in the application setup and protect against this?
I'm still getting a grasp on the OpenID Connect and OAUTH 2.0 finer points so forgive me if this question has an obvious answer.
Adal.js uses the Implicit flow (as per OpenID connect / oAuth 2 specifications) and exposing the ClientID (and tenant id of AAD) doesn't pose any security risk.
While registering the Clients in Azure AD administration panel, we specify a Redirect URI for the client. This is the Application URL for which users will get redirected after successful authentication.
So even if a malicious client tries to use your clientid and tenant id, the users will be redirected back to the registered URI(which is your app) after authentication and not to the malicious site
In implicit flow the application doesn't collect any username / password, IDP/OP (i.e AAD) manages this part - so user credentials won't be compromised as well
**For other flow types (Authorization code, Client credentials,etc) we have something called client-password along with ClientID. This shouldn't be exposed to public clients.

Secure REST API without user authentification (no credentials)

I've been struggling for 2 days now on how to secure a REST API without user authentification.
What does it mean ?
In my AngularJS application I identify an user by sending a GET request to an existing service (companydomain/userinfo) which I must use. I'm not sure how this work since I am not the author of this piece of code but the point is that I get the information about the user in the response as JSON (active directory name, phone in the company...).
This is all I have to identify an user.
What I did
Now, I found a lot of resources talking about OAuth, unique token, etc. but nothing seems to match with my issue. I implemented a token system but it's plain useless since I can't be sure of the authenticity of the requester.
User open the application. Application ask the service about the information related to the user. companydomain/userinfo
Application request a token to the server (nodejs & express), based on the information returned. /api/token/get/{user_info}
Server generates an unique token and store it in memory with expiration date and owner. The server also check in the table "authorized users" if the user exists (based on the active directory name), if not a new entry is added to it.
Application send the token along each request to the API. /api/entry/delete/{entry_id}
I think you see what is wrong here, an attacker could easily make a corrupted request to the API to get a legit token. So my question is :
How can I manage to secure my API since users don't use credentials to authentify ?
I hope my question is clear enough and at this point I am not even sure I can get around this issue without adding a credentials system.
You might want to look at Passport. It is a platform that allows you to easily add authentication to your application. There are many authentication strategies available. I am using Passport in a Node.js application implementing my own hmac strategy.
To authenticate, the client request includes an API ID to identify who the caller is and also includes an signature of a specified part of the message that includes things like the HTTP method, the API ID, a date value and some other header values, like maybe content-type. What data to include in the string to sign is up to you in your implementation, but the client and server must create and sign the same strings for the authentication to work. The signature is created by doing an hmac hash of the string using a shared secret.
On the server side, you use the API ID to retrieve the shared secret (possibly from a database or the filesystem) and perform the same hash on the request. If the hmac values match then you've authenticated the request. To prevent playback attacks, the date is included in the signed part of the request and must be within a certain window of the server's current time. For example, you might reject the request if the timestamp is more than 30 seconds old.
To enable a new user of your API, you generate a new API ID and shared secret. You give both of those to your API user and you store them for look up in your database or filesystem. The user must sign the requests with the shared secret and include the ID in the request.
The Hawk strategy provides much of this functionality, but we decided to roll our own hmac strategy.
Because you say that the user info endpoint returns active directory name, I assume you're on the Windows platform.
If so, why not use Windows integrated authentication (Kerberos) to authenticate your users without asking them for credentials? This will only work within your active directory domain, but is completely transparent to your service.
You can still call the user info endpoint and verify that the info it returns is for the same user that is calling your REST service.
If you need to call services that do not support Windows integrated auth, you could generate a security token (sign it to guarantee integrity) and make the other services trust this token.

Resources