MS Teams
This guide is for the customer’s Microsoft 365 administrator and the Edmingle administrator. Follow it in order. When it is complete, tutors can schedule an MS Teams session in Edmingle, students can join without a Microsoft account, and Edmingle can close the session, mark attendance, and pull the recording.
Edmingle does not use a shared Edmingle Teams tenant. Every meeting is created in your Microsoft 365 tenant, with your app registration and your organizer user.
1. What you are setting up
| Piece | Who owns it | What it does |
|---|---|---|
| Microsoft 365 tenant | You | Hosts the meetings, licences, and policies |
| Entra app registration | You | Lets Edmingle call Microsoft Graph with an app secret. No user signs in to this app |
| Organizer user | You | The Microsoft user that owns every class meeting |
| Application access policy | You | Lets that app act on the organizer’s meetings. Required. Permissions alone are not enough |
| Edmingle MS Teams integration | You, in Edmingle | Stores tenant id, client id, client secret, and organizer id |
| Students | Your learners | Join from Edmingle. They do not need a Microsoft account |
| Tutors | Your teachers | Start the class from Edmingle. Host controls belong to the organizer account |
2. How a class behaves
Read this before setup. Several items look like product bugs and are Microsoft limits.
- A tutor or admin opens the session in Edmingle. Edmingle creates one Teams meeting under the organizer user and gives everyone the same join link.
- A student who clicks Join in Edmingle is marked present at that moment.
- The student opens Teams. If they have no Microsoft account, they join as a guest and type a name. That name is not used for attendance.
- The meeting is not ended from Edmingle. Someone must end it in the Teams client.
- After Teams has actually ended, an admin can end the session in Edmingle. Students who never clicked Join are marked absent.
- Time spent inside Teams is not stored. Attendance threshold does not apply to MS Teams and is hidden when MS Teams is selected.
- If auto-record is on, the recording is pulled after the call has ended and attached to the session. A transcript is pulled only when your tenant allows Graph to read transcripts.
Who is the host
The host is the organizer user configured in Edmingle, not whichever tutor is logged into Edmingle.
- A tutor who signs into Teams with a different user in the same tenant can present (share, mute) but is not the meeting owner.
- A tutor whose Teams browser session is expired, or who joins without that work account, joins as a guest and will not have presenter controls.
- Students are attendees. They cannot end the meeting or manage others.
If tutors must have full host controls, the organizer user must be that tutor’s Microsoft account, or you must accept that host controls stay with the shared organizer account. Edmingle does not add co-organizers.
3. Before you start
You need all of the following.
| Requirement | Why |
|---|---|
| Microsoft 365 tenant with Teams | Meetings are created in this tenant |
| Global Administrator, or equivalent rights to register apps, grant admin consent, and change Teams policies | Setup cannot be finished with a normal user |
| One licensed user who will own the meetings | The user needs a Teams licence. Meeting size follows this user’s licence, usually 300 people, sometimes 1,000 |
| PowerShell with the Microsoft Teams module | The application access policy and several meeting policies cannot be set in the portal alone |
| Edmingle admin access | To paste the credentials and run Test connection |
| A public HTTPS Edmingle domain | Microsoft sends meeting-ended notifications to https://<your-edmingle-host>/webhooks/msteams/TeamsWebHook.php. Localhost and private IPs will not work |
Decide the organizer before creating the app policy. Changing the organizer later means granting the policy to the new user. Old meetings stay owned by the old user.
Do not use a personal Microsoft account (@outlook.com, @hotmail.com, or a personal Gmail used to sign into Microsoft). It cannot be the organizer of these meetings.
4. Create the organizer user
- In the Microsoft 365 admin center, create or choose a user, for example
teams-classes@yourdomain.com. - Assign a licence that includes Microsoft Teams.
- Sign in once as that user and finish any first-run prompts. The mailbox and Teams app must exist. An unlicensed or never-activated user will fail when Edmingle creates a meeting.
- In Microsoft Entra admin center → Identity → Users → open that user.
- Copy Object ID. This is the value Edmingle calls Organizer user id.
Keep the account’s password and MFA with your IT team. Edmingle never signs in as this user. If the account is deleted, disabled, or loses its Teams licence, new classes stop working and existing recordings may become unreadable.
5. Register the Edmingle app
- Entra admin center → Identity → Applications → App registrations → New registration.
- Name it something your admins will recognise, for example
Edmingle Teams. - Supported account types: Accounts in this organizational directory only.
- Leave Redirect URI empty. This app uses a secret, not a user login.
- Register.
- On Overview, copy:
- Application (client) ID → Edmingle Client id
- Directory (tenant) ID → Edmingle Tenant id
- Certificates & secrets → New client secret.
- Choose an expiry your team will track (24 months is typical). Copy the Value immediately. Microsoft shows it only once. This is the Edmingle Client secret. The Secret ID is not the secret.
Store the secret in a password manager. Do not email it or put it in a ticket.
6. Grant Graph permissions
Entra → your app → API permissions → Add a permission → Microsoft Graph → Application permissions.
Add these. They must be Application, not Delegated.
| Permission | Required for |
|---|---|
OnlineMeetings.ReadWrite.All |
Creating the class meeting |
OnlineMeetingArtifact.Read.All |
Knowing the call has ended |
CallRecords.Read.All |
Receiving the meeting-ended notification and reading the call |
OnlineMeetingRecording.Read.All |
Saving the class recording in Edmingle |
OnlineMeetingTranscript.Read.All |
Saving the transcript |
Files.Read.All |
Downloading a recording when Microsoft stores the file in the organizer’s OneDrive |
Then click Grant admin consent for
User.Read and User.Read.All are not required. Do not add broad directory permissions “just in case”.
7. Allow the app to manage the organizer’s meetings
Admin consent is not sufficient. Microsoft also requires an application access policy that names this app and this organizer. This is PowerShell only.
Install once:
Install-Module MicrosoftTeams -Scope CurrentUser
Sign in as a Teams administrator. Use a normal desktop PowerShell window. Cloud Shell often cannot do interactive sign-in.
Connect-MicrosoftTeams
Confirm you are in the customer tenant, not another Azure subscription:
Get-CsTenant | Format-List DisplayName, TenantId
TenantId must match the Directory (tenant) ID from the app registration.
Create the policy once. Replace the app id:
New-CsApplicationAccessPolicy `
-Identity "Edmingle-Live-Class" `
-AppIds "<application-client-id>" `
-Description "Allows Edmingle to create and read live-class meetings"
Grant it to the organizer. Use the organizer’s sign-in address:
Grant-CsApplicationAccessPolicy `
-PolicyName "Edmingle-Live-Class" `
-Identity "teams-classes@yourdomain.com"
Confirm:
Get-CsOnlineUser -Identity "teams-classes@yourdomain.com" |
Format-List ApplicationAccessPolicy
The result must be Edmingle-Live-Class. Policy assignment can take up to 30 minutes, sometimes longer. If Test connection works but creating a class returns an access or policy error, wait and retry before changing the app.
8. Allow students to join without a Microsoft account
Students do not have accounts in your tenant. Both of the settings below must allow anonymous join. If either is off, students see Sign in to join the meeting.
Set-CsTeamsMeetingConfiguration -Identity Global -DisableAnonymousJoin $false
$policy = (Get-CsOnlineUser -Identity "teams-classes@yourdomain.com").TeamsMeetingPolicy
if ([string]::IsNullOrWhiteSpace($policy)) { $policy = "Global" }
Set-CsTeamsMeetingPolicy -Identity $policy -AllowAnonymousUsersToJoinMeeting $true
Get-CsTeamsMeetingConfiguration -Identity Global | Format-List DisableAnonymousJoin
Get-CsTeamsMeetingPolicy -Identity $policy | Format-List AllowAnonymousUsersToJoinMeeting
Expected: DisableAnonymousJoin : False and AllowAnonymousUsersToJoinMeeting : True.
The same change exists in Teams admin center:
- Meetings → Meeting settings → Anonymous users can join a meeting → On
- Meetings → Meeting policies → the policy on the organizer → Anonymous users can join a meeting → On
These changes can take a few hours. Test with a new session. An old join link can keep the previous behaviour.
9. Recording and transcripts
Recording
On the organizer’s meeting policy:
Set-CsTeamsMeetingPolicy -Identity $policy -AllowCloudRecording $true
Edmingle asks Teams to record automatically. The file is not available at the moment the call ends. Edmingle fetches it after Microsoft publishes the recording. Large files can take longer.
Tell learners that the class is recorded. Recording laws and your own privacy notice are your responsibility.
Transcripts
Transcription must be allowed, and Graph must be allowed to read the transcript. The second switch is off by default in many tenants.
Set-CsTeamsMeetingPolicy -Identity $policy -AllowTranscription $true
Set-CsTeamsMeetingConfiguration -Identity Global -EnableGraphTranscriptAccess $true
If Graph transcript access is off, the class still runs and the recording can still be saved. The transcript step fails with an error similar to “Graph API access to transcripts is disabled for this tenant”. That is a tenant setting, not an Edmingle outage.
If the tenant disallows speaker names in transcripts, Edmingle saves the transcript without speaker names.
10. Enter the credentials in Edmingle
- Sign in to Edmingle as an administrator.
- Open Settings → Integrations → MS Teams.
- Enter:
| Edmingle field | Microsoft value |
|---|---|
| Tenant id | Directory (tenant) ID |
| Client id | Application (client) ID |
| Client secret | Secret Value from Certificates & secrets |
| Organizer user id | Organizer user’s Object ID |
- Save and turn the integration on.
- Click Test connection.
Test connection only proves that the tenant id, client id, and secret can obtain a token. It does not prove the application access policy, the organizer licence, anonymous join, or recording. Those are proved by the class test in the next section.
The secret is never shown again in Edmingle. To rotate it, create a new secret in Entra, paste the new value, and save. Leave the secret box empty on later saves if you are not changing it.
After a successful save, Edmingle registers a Microsoft subscription so it is told when calls end. The notification address is:
https://<your-edmingle-host>/webhooks/msteams/TeamsWebHook.php
That URL must be reachable from the public internet and must be the same host your institution uses in the browser. If Test connection succeeds but the subscription warning appears, send that warning text to Edmingle support. Do not keep creating new app registrations.
11. Prove the setup with one real class
Use a brand-new session. Do not reuse a meeting created before the policy changes.
- In Edmingle, schedule a live session and choose MS Teams. Attendance threshold must not be offered for this provider.
- As a tutor, open the session and start it. Edmingle should return a Teams join link without an error.
- In a private browser window, with no Microsoft login, open the student join flow. You should reach the Teams pre-join screen and be able to enter a name. You should not be forced to sign in.
- In another window, sign in to Teams as the organizer and join. That user should have host controls.
- If a tutor uses a different work account, sign out of Teams completely, sign in as that tutor, and join from Teams. They should appear under their work name. They can present. They should not be labelled as a guest.
- End the call inside Teams. Ending it only in Edmingle will be rejected while Teams still considers the call live. The message is: the meeting is still running in Microsoft Teams; end it there first.
- End the session in Edmingle. The student who clicked Join is present. A student who never clicked Join is absent.
- Wait, then confirm the recording appears on the session. Transcript appears only if section 9 was completed.
If step 3 fails, section 8 is not in effect yet. If step 2 fails with a policy or authorization error, section 7 is missing or not propagated. If step 5 shows the tutor as a guest, that browser is not actually signed into the work account.
12. Day-to-day use
Tutor
- Start the session from Edmingle.
- Join Teams with the organizer account when host controls are required. Otherwise join with a work account in the same tenant.
- Teach, then click End meeting in Teams.
- End the session in Edmingle only after Teams has ended.
Student
- Click Join in Edmingle. That click is what marks them present.
- On the Teams screen, enter their name and join. No Microsoft account is required.
- Closing the Edmingle tab without clicking Join leaves them absent, even if someone later forwards them the Teams link outside Edmingle.
Administrator
- Renew the client secret before it expires. An expired secret stops new meetings and recording downloads. Edmingle cannot warn Microsoft about your secret expiry.
- Do not delete the organizer user.
- Do not remove admin consent or the application access policy.
- If you change the Edmingle domain, tell Edmingle support. The Microsoft notification URL is tied to the host.
13. Attendance rules
| Event | Result |
|---|---|
| Student clicks Join in Edmingle | Present |
| Student never clicks Join | Absent, once the session is closed |
| Student joins Teams from a link that bypassed Edmingle | Not marked present. Edmingle cannot see an anonymous guest’s identity |
| Time inside the meeting | Not stored |
| Attendance threshold | Not used for MS Teams |
This is intentional. A normal Teams meeting has no per-student registration. Anonymous guests are only a display name they typed themselves, so Edmingle does not match attendance by name.
14. Risks and limits
| Risk | What happens | What to do |
|---|---|---|
| Client secret leaks or expires | Anyone with the secret can call Graph as your app. An expired secret breaks classes | Store it in a password manager. Rotate it in Entra and paste the new value into Edmingle. Remove the old secret after the new one works |
| Organizer loses licence, is disabled, or is deleted | New meetings fail. Recordings owned by that user may be lost | Use a dedicated service account. Do not tie classes to a person who may leave |
| One organizer for every class | All meetings, recordings, and chat ownership sit with that account. Meeting size is that account’s licence | Size the licence for your largest class. 300 is the common cap; some licences allow 1,000 |
| Tutor is not the organizer | Tutor does not get host controls | Join as the organizer when host controls are required |
| Anonymous join turned off later | Students suddenly see a sign-in wall. Existing code does not change | Re-check both settings in section 8. Test a new meeting |
| Stale Teams login | A tutor who looks signed in is joined as a guest and cannot present | Sign out of Teams, close the browser, sign in again as the work account, then join |
| Attendance is join-click, not presence in Teams | A student can be present in Edmingle after clicking Join and then never enter Teams. A student who only opens a forwarded Teams link stays absent | Tell students to use the Edmingle Join button |
| No duration and no threshold | You cannot mark absent because someone left after five minutes | Do not promise Zoom-style threshold reports for Teams |
| Edmingle cannot end the Teams call | Ending the session in Edmingle while people are still in Teams is rejected | End the meeting in Teams first |
| Recording delay or failure | Microsoft can take time to publish the file. Missing Files.Read.All, recording policy, or access policy blocks the download |
Confirm section 6 and section 9. Check the session again later before treating it as lost |
| Transcripts disabled at tenant level | Recording works, transcript does not | Run the transcript commands in section 9 |
| Application access policy missing | Token test succeeds, creating a meeting fails | Complete section 7 and wait for propagation |
| Wrong tenant in PowerShell | You change a different organization’s policies | Compare Get-CsTenant TenantId with the app’s Directory (tenant) ID |
| Meeting policy propagation | A correct command still fails for a while | Wait, then create a new session. Do not keep recreating the app |
| Privacy and recording consent | Classes are recorded into your tenant and then into Edmingle | Update your learner notice. Restrict who can open session recordings |
| Capacity | People above the organizer’s Teams limit cannot join. Teams does not tell Edmingle which person was refused | Keep class size inside the licence. Edmingle’s warning uses 300 unless your licence cap has been set to 1,000 with Edmingle support |
| Webhook host change | Meeting-ended events stop. Sessions stay open until the safety check runs | Keep the Edmingle domain stable. Ask support after a domain cutover |
| Lobby | Students are not held in a lobby | Anyone with the join link can enter while the meeting is live. Treat the link as class access |
Edmingle will not register students with Microsoft, will not create a personal join link per student, and will not turn a tutor into host unless that tutor is the configured organizer. Those are limits of the Teams meeting product used here.
15. Troubleshooting
| What you see | Likely cause | Action |
|---|---|---|
| Test connection says credentials were rejected | Wrong tenant id, client id, or secret, or secret expired | Create a new secret value and paste tenant id, client id, and the new secret |
| Test connection works, creating a class fails with authorization or application access policy | Section 7 missing, granted to the wrong user, or not propagated | Re-check ApplicationAccessPolicy on the organizer. Wait 30 minutes. Retry with a new session |
| Student must sign in to join | Anonymous join is off | Section 8. Confirm both values, wait, test a new meeting |
| Tutor is signed in but joins as a guest and cannot host | Expired browser session, personal Microsoft account, or the tutor is not the organizer | Sign out and back in with the work account. For host controls, join as the organizer user |
| Edmingle says the Teams meeting is not ended yet | The call is still live in Teams | End it in the Teams client, wait a short time, end the session in Edmingle again |
| Recording missing | Recording policy, file permission, or Microsoft has not published it yet | Confirm AllowCloudRecording and Files.Read.All. Check again later |
| Transcript missing, recording present | Graph transcript access or transcription policy is off | Section 9 |
| Present / absent looks wrong | Attendance follows the Edmingle Join click, not the Teams participant list | See section 13 |
When you contact Edmingle support, send:
- Approximate time of the attempt
- Whether Test connection succeeded
- The exact error text, with the client secret removed
- Whether a private window could join without signing in
- Output of the confirmation commands in sections 7 and 8, with no secrets included
16. Setup checklist
Organizer user exists, has signed in once, and has a Teams licence
Organizer Object ID copied
App registered in this tenant only
Tenant id, client id, and secret value copied and stored safely
Six application permissions added
Admin consent granted
Application access policy created and granted to the organizer
Anonymous join enabled at tenant and on the organizer’s meeting policy
Cloud recording enabled
Transcription and Graph transcript access enabled, if transcripts are required
Credentials saved in Edmingle and Test connection succeeded
New test class: student joins without an account
New test class: organizer has host controls
Call ended in Teams, then session ended in Edmingle
Present and absent match who clicked Join
Recording appears on the session
Secret expiry date is on the IT calendar
17. Commands in one place
Run after Connect-MicrosoftTeams, and only after Get-CsTenant shows the correct tenant. Replace the two placeholders.
New-CsApplicationAccessPolicy `
-Identity "Edmingle-Live-Class" `
-AppIds "<application-client-id>" `
-Description "Allows Edmingle to create and read live-class meetings"
Grant-CsApplicationAccessPolicy `
-PolicyName "Edmingle-Live-Class" `
-Identity "<organizer-sign-in-address>"
Set-CsTeamsMeetingConfiguration -Identity Global -DisableAnonymousJoin $false
Set-CsTeamsMeetingConfiguration -Identity Global -EnableGraphTranscriptAccess $true
$policy = (Get-CsOnlineUser -Identity "<organizer-sign-in-address>").TeamsMeetingPolicy
if ([string]::IsNullOrWhiteSpace($policy)) { $policy = "Global" }
Set-CsTeamsMeetingPolicy -Identity $policy -AllowAnonymousUsersToJoinMeeting $true
Set-CsTeamsMeetingPolicy -Identity $policy -AllowCloudRecording $true
Set-CsTeamsMeetingPolicy -Identity $policy -AllowTranscription $true
If New-CsApplicationAccessPolicy says the policy already exists, skip that one command. Do not create a second policy for the same app.
Confirm:
Get-CsOnlineUser -Identity "<organizer-sign-in-address>" |
Format-List ApplicationAccessPolicy, TeamsMeetingPolicy
Get-CsTeamsMeetingConfiguration -Identity Global |
Format-List DisableAnonymousJoin, EnableGraphTranscriptAccess
Get-CsTeamsMeetingPolicy -Identity $policy |
Format-List AllowAnonymousUsersToJoinMeeting, AllowCloudRecording, AllowTranscription