Forum Discussion
API to access MS forms
This is my set up (set up from scratch to test it), hopefully it can help narrow down the problem:
- Set up a basic App registration (single tenant, no redirect URI).
- Copy the application (client) ID
- Set up a secret. Copy the secret.
- NO API PERMISSIONS REQUIRED (as of writing this). This is strange, but for some reason, it works (for now)
- log into forms through your browser, then open a new tab and go to the following: https://forms.office.com/formapi/api/userInfo
- Grab the (user) id from that response, and use it in the following: https://forms.office.com/formapi/api/{Tenant_id}/users/{User_id}/forms
- Grab a (form) id from that response and now try the following: https://forms.office.com/formapi/api/{Tenant_id}/users/{User_id}/forms
Testing in postman, authenticate using the following and copy the token:
POST to "https://login.microsoftonline.com/{TenantID}/oauth2/v2.0/token"
Body:
- grant_type = client_credentials
- client_id = {app_id copied}
- client_secret = {app_secret copied}
- scope = https://forms.office.com/.default
- (@mpheasent used this with success as well: api://forms.office.com/c9a559d2-7aab-4f13-a6ed-e7e9c52aec87/.default)
9. Replicate the responses call with postman (note the URL encoding of (''):
GET "https://forms.office.com/formapi/api/{Tenant_id}/users/{user_id}/forms%28%27{Form_id}%27%29/responses"
Headers:
- Authorization = Bearer {token}
Haven't figured out a single call to to get all forms for all users yet either. Hope this helps someone nonetheless.
- NunoN370Feb 10, 2024Copper Contributor
I've actually built an API to create MS Forms and read responses programmatically, by reverse engineering chrome developer tools.
It was working fine the last time I used it, although I haven't documented/fine tuned it that much.
- amitkumar4Feb 09, 2024Copper Contributor
BinaryBotany Is this really working? I am using same setup and it doesn't work
{"error": "invalid_resource","error_description": "AADSTS500011: The resource principal named api://forms.office.com/<tenat> was not found in the tenant named <####>. This can happen if the application has not been installed by the administrator of the tenant or consented to by any user in the tenant. You might have sent your authentication request to the wrong tenant. Trace ID: 4b98a3c5-3a61-452d-82c8-3dcae3f62b00 Correlation ID: c40cdd68-0718-47b0-9227-80b7b0553c3f Timestamp: 2024-02-09 18:56:00Z","error_codes": [500011],"timestamp": "2024-02-09 18:56:00Z","trace_id": "4b98a3c5-3a61-452d-82c8-3dcae3f62b00","correlation_id": "c40cdd68-0718-47b0-9227-80b7b0553c3f","error_uri": "https://login.microsoftonline.com/error?code=500011"} - KeithW_AUJul 18, 2023Copper ContributorYep, same issue today.
Somethings broken with SP Auth, still works via the signed in user and manually browsing.
Did anyone else figure out what went wrong?
Tried full Application and Delegated permissions for "Microsoft Forms" in AAD. - BinaryBotanyDec 02, 2022Copper Contributor
Hey audriga,
I tested my old code for this and ended up getting the same 403 error. Looks like something has changed in the backend.... again.
The calls still work via the web browser once signed in to Forms, so the API still works. It must be something to do with the service principal authentication.
Sorry!
- mpheasantDec 01, 2022Copper ContributorIn my case its a server side (daemon/ confidential client) app in python, with a user id (forms_user) and password (forms_pass) for an account with admin access to the form, the code looks something like:
-----------
app = msal.ConfidentialClientApplication(
client_id,
client_credential=secret,
authority=authority
)
token = app.acquire_token_silent([scope], account=None)
if not result:
# No suitable token exists in cache. Let's get a new one from AAD.
token = app.acquire_token_by_username_password(forms_user, forms_pass, [scope]) - mpheasantDec 01, 2022Copper Contributor
if your form is protected then using oauth2 like that doesnt support supplying the password in that way and will do the redirect to show the logon form of the tenant.
There are ways to get a token with a userid/password, one is:
https://learn.microsoft.com/en-au/azure/active-directory/develop/v2-oauth-ropc
but you're probably better off with something like the "Daemon app that calls web APIs" scenario:
https://learn.microsoft.com/en-us/azure/active-directory/develop/authentication-flows-app-scenarios#scenarios-and-supported-authentication-flows - audrigaDec 01, 2022Copper Contributor
Hi!
I tried to do exactly as you explained:- I set up a basic app registration, single tenant, no redirect URI
- I got the application ID
- I created a secret
- I actually added all Forms related permissions I found
- I got the user ID
- I requested a token with: curl -X POST -H "Content-Type: application/x-www-form-urlencoded" -d 'client_id=<clientId>&scope=https%3A%2F%2Fforms.office.com%2F.default&client_secret=<clientSecret>&grant_type=client_credentials' 'https://login.microsoftonline.com/<tenantId>/oauth2/v2.0/token'
- I tried to request my forms with: curl -v -X GET -H 'Authorization: Bearer <token>' https://forms.office.com/formapi/api/<tenantId>/users/<userId>/forms
I am getting an HTTP 403 on the last request. Any idea?
Thanks
- OleksiihoSep 02, 2022Copper Contributor
Maybe somebody will find it useful so I'll leave it here.
Unfortunately forms API doesn't work well for S2S solutions, simply because there's no way to get Group forms, and the problem is that sooner or later every user form get transferred to group ownership.
So if you wanna to build something on server side with full support of any forms your best bet is using automation solutions, either it's Azure Logic Apps, or Power Automate, because they have native connectors to forms, and actions which can perform any http request as long as integration account does have O365 license.
Also, there's always a choice to use MSAL and perform authentication using login / password of integration account (with assigned license of course), so you'll be able obtain appropriate user token silently, but I strongly suggest not to look into this avenue
- OleksiihoAug 22, 2022Copper Contributor
When you logged in to the Forms portal, the browser makes different requests depending on form ownership type. Per my understanding "ownerId" field can contain 2 types of owners: individual users (who own / created the form initially), or Office 365 group (when user delegates form access / permissions / ownership to whole bunch of users i.e. group).
So, in browser, if the formOwnerUserId is user's oid, it uses the following URL:
"https://forms.office.com/formapi/api/<tenantId>/users/<formOwnerUserId>/forms"
It's fine and works the same in delegated scenario and S2S
But, if the formOwnerGroupId is office 365 group's oid, it uses another url segment (/groups/ instead of /users/):
"https://forms.office.com/formapi/api/<tenantId>/groups/<formOwnerGroupId>/forms"
And that's where the problem lies with S2S.. Apparently it doesn't recognize /groups/ segment and still requires /users/ one, but when used /users/ with formOwnerGroupId it just throws error because apparently it can't treat groupId as userId, meaning that S2S can't grab any data on form which is under group ownership
You can get data using delegated access though, but still..
- mpheasantAug 22, 2022Copper Contributor
I havent seen one like that so cant say.
You should be able to find the API URL by going to that form in the browser and using "Inspect" like I mention in my comment under note 2/:
- OleksiihoAug 21, 2022Copper Contributor
Thanks for your tips. Getting form data is pretty straightforward if OwnerId field is actually ObjectId of the user. But unfortunately "https://forms.office.com/formapi/api/<tenant_Id>/users/<form_owner_id>/forms" doesn't work if the form_owner_Id is a group ObjectId. I've tried to replace users segment with groups but to no avail
Some forms in my organization are under group ownership and I'm at loss how to get data about them without using delegated access