Inject (own) Azure Ad id_token in Office Scripts external fetch request - azure-active-directory

Looking to make an Azure-AD authenticated external API call from within an Office-Scripts-enabled Excel Online workbook. Access to the workbook is secured to members of my organization only, so interaction with the workbook is possible only via an (Azure-AD) authenticated session.
Do you have any idea on the user's own id_token could be injected in the request? This way, the receiving end would be able to validate that the request originated from an authenticated user, by validating the token's signature.
Kind regards

There is no supported way to inject the user token into an Office Script right now. For authenticated calls, the recommended approach is to create a Power Automate Flow that uses the appropriate credentials to fetch whatever data the Office Script needs, then pass it to the script via its optional params in main, perform processing, and either write to the document or return the value from the script so the subsequent Flow steps can consume it. Does that work for your scenario?

Related

Client Side Rendering and API Security [duplicate]

I'm developing the restful web app that using some popular web framework on the backend, say (rails, sinatra, flask, express.js). Ideally, I want to develop client side with Backbone.js. How do I let only my javascript client side interact with those API calls? I don't want those API calls to be public and be called by curl or simply by entering the link on browser.
As a first principle, if your API is consumed by your JS client, you have to assume, that it is public: A simple JS debugger puts an attacker into a position, where he can send a byte-for-byte identical request from a tool of his choice.
That said, if I read your question correctly, this is not, what you want to avoid: What you really don't want to happen is, that your API is consumed (on a regular basis) without your JS client being involved. Here are some ideas on how to if not enforce, then at least encourage using your client:
I am sure, your API has some sort of authentication field (e.g. Hash computed on the client). If not, take a look at This SO question. Make sure you use a salt (or even API key) that is given to your JS client on a session basis (a.o.t. hardcoded). This way, an unauthorized consumer of your API is forced into much more work.
On loading the JS client, remember some HTTP headers (user agent comes to mind) and the IP address and ask for reauthentication if they change, employing blacklists for the usual suspects. This forces an attacker to do his homework more thoroughly again.
On the server side, remember the last few API calls, and before allowing another one, check if business logic allows for the new one right now: This denies an attacker the ability to concentrate many of his sessions into one session with your server: In combination with the other measures, this will make an abuser easy detectable.
I might not have said that with the necessary clarity: I consider it impossible to make it completely impossible for an abuser to consume your service, but you can make it so hard, it might not be worth the hassle.
You should implement some sort of authentication system. One good way to handle this is to define some expected header variables. For example, you can have an auth/login API call that returns a session token. Subsequent calls to your API will expect a session token to be set in an HTTP header variable with a specific name like 'your-api-token'.
Alternatively many systems create access tokens or keys that are expected (like youtube, facebook or twitter) using some sort of api account system. In those cases, your client would have to store these in some manner in the client.
Then it's simply a matter of adding a check for the session into your REST framework and throwing an exception. If at all possible the status code (to be restful) would be a 401 error.
There's an open standard now called "JSON Web Token",
see https://jwt.io/ & https://en.wikipedia.org/wiki/JSON_Web_Token
JSON Web Token (JWT) is a JSON-based open standard (RFC 7519) for
creating tokens that assert some number of claims. For example, a
server could generate a token that has the claim "logged in as admin"
and provide that to a client. The client could then use that token to
prove that they are logged in as admin. The tokens are signed by the
server's key, so the server is able to verify that the token is
legitimate. The tokens are designed to be compact, URL-safe and usable
especially in web browser single sign-on (SSO) context. JWT claims can
be typically used to pass identity of authenticated users between an
identity provider and a service provider, or any other type of claims
as required by business processes.[1][2] The tokens can also be
authenticated and encrypted.[3][4]
Set a SESSION var on the server when the client first loads your index.html (or backbone.js etc.)
Check this var on the server-side on every API call.
P.S. this is not a "security" solution!!! This is just to ease the load on your server so people don't abuse it or "hotlink" your API from other websites and apps.
Excuse me #MarkAmery and Eugene, but that is incorrect.
Your js+html (client) app running in the browser CAN be set up to exclude unauthorized direct calls to the API as follows:
First step: Set up the API to require authentication. The client must first authenticate itself via the server (or some other security server) for example asking the human user to provide the correct password.
Before authentication the calls to the API are not accepted.
During authentication a "token" is returned.
After authentication only API calls with the authentication "token" will be accepted.
Of course at this stage only authorized users who have the password can access the API, although if they are programmers debugging the app, they can access it directly for testing purposes.
Second step: Now set up an extra security API, that is to be called within a short limit of time after the client js+html app was initially requested from the server. This "callback" will tell the server that the client was downloaded successfully. Restrict your REST API calls to work only if the client was requested recently and successfully.
Now in order to use your API they must first download the client and actually run it in a browser. Only after successfully receiving the callback, and then user entry within a short frame of time, will the API accept calls.
So you do not have to worry that this may be an unauthorized user without credentials.
(The title of the question, 'How do I secure REST API calls', and from most of what you say, that is your major concern, and not the literal question of HOW your API is called, but rather BY WHOM, correct?)
Here's what I do:
Secure the API with an HTTP Header with calls such as X-APITOKEN:
Use session variables in PHP. Have a login system in place and save the user token in session variables.
Call JS code with Ajax to PHP and use the session variable with curl to call the API. That way, if the session variable is not set, it won't call and the PHP code contains the Access Token to the API.

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

Google Calendar API FreeBusy Access Using Service Account

We have built an application that is attempting to use a Service Account to access the google Calendar API. We manage the application ourselves, but the calendars we are trying to access are on a separate GSuite account. We have had the GSuite admin follow the steps here to allow access to our app based on client ID and the auth scope of "https://www.googleapis.com/auth/calendar.readonly."
Now when using the service account to attempt to access user calendar data, I'm a bit confused about how to properly format the request. Specifically, if I don't include a "sub" parameter, the request works in the sense that I am granted a token and I'm able to proceed to make a subsequent request to access calendars. However in that subsequent request, I am returned with errors on users calendars indicating not found i.e. I don't have access. Below is the request:
String jwtClaimset = '{'+
'"iss":"xxxxx#service-account.com",'+
'"sub":"xxxxxx#xxxx.com",'+
'"scope":"https://www.googleapis.com/auth/calendar.readonly",'+
'"aud":"https://www.googleapis.com/oauth2/v4/token",'+
'"exp":'+expTime+','+
'"iat":'+requestTime+
'}';
However, then if I include a specific email/username from the GSuite account to "impersonate", I am not able to request the token at all, I'm presented with the below error:
"error_description": "Client is unauthorized to retrieve access tokens using this method."
So my question is, do I need the sub parameter to access any of the users calendars in the GSuite and if so do you know why that error is being presented?
And I have no idea what happened maybe it just took time for the GSuite permissions/access to update but now this is working.
For note, we are using the sub parameter and its working using that (as we suspected we needed).

Secure REST Unauthenticated Account Creation

I'm designing a REST API and I've hit somewhat of an odd point. 99% of this API will be secured, but there are a few functions that need to be publicly accessible. These pertain to account creation, and initial password setting. Once they have credentials, they can access the rest of the API.
The endpoint that allows a user to create a new account via a signup form is unauthenticated. Securing this endpoint isn't really possible because I'm using AngularJS on top of nodejs, and dog-fooding my API via AJAX calls. This means I can't hide credentials anywhere to access the AccountCreation endpoint. Currently, I have the webform make an AJAX call to another endpoint and create a token that says to form is valid. Upon submission that token is validated, then removed from the database. However, this token endpoint is obviously visible in code, so not much security there. Email verification is used to 'activate' the account, then the user is given a one-time link to set their initial password, which also resides on an unauthenticated endpoint(but requires the token sent in the email).
I guess my worry is someone spamming the 'CreateAccount' endpoint, and making a bunch of accounts. In reality I guess they could simply do this via the webform as well. Is this a valid security concern? How do most places handle unauthenticated account creation webforms?
Edit: the final application will be run over https

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