Skip to content

Microsoft Teams Certificate Authentication on Linux

directorcia edited this page Oct 22, 2026 · 1 revision

Purpose

o365-connect-tms-cert-linux.ps1 creates and uses file-based X.509 certificates to connect to Microsoft Teams with application (app-only) authentication from Linux. It is the Linux counterpart of o365-connect-tms-cert.ps1 and avoids the Windows certificate store: the script loads an encrypted PFX into memory and passes the resulting certificate object to Connect-MicrosoftTeams.

The script has two mutually exclusive modes:

  • Generate: create a certificate and export an encrypted private-key PFX plus a public DER CER file.
  • Connect: load a PFX, validate it, and establish a Teams PowerShell connection in the current PowerShell process.

Generation works without installing PowerShell modules. Optional Entra app provisioning requires Microsoft Graph PowerShell authentication. Connecting requires the Microsoft Teams PowerShell module. The script does not deploy a service, start a persistent process, or save the PFX password.

Requirements and Compatibility

  • Linux and PowerShell 7.4 or later.
  • MicrosoftTeams 5.0.0 or later for a Teams connection.
  • Microsoft.Graph.Authentication 2.0.0 or later only when using -ProvisionEntraApp.
  • Network access to PowerShell Gallery, Microsoft Graph, and Microsoft Teams when installing modules, provisioning, or connecting.

Missing modules are installed for CurrentUser, without sudo, when interactive installation is allowed. In headless mode, required modules must already be installed. An already-loaded module that is older than the required version causes an error; start a fresh pwsh session after installing a newer version.

Use the Windows counterpart on Windows. After a successful connection, run Teams cmdlets in the same PowerShell session. The connection ends when that process exits.

Modes and Workflows

1. Generate a certificate

-GenerateLocalCertificate creates a self-signed RSA-2048 certificate using SHA-256 and the Digital Signature key usage. The certificate is valid for the requested number of years, beginning a few minutes before generation to avoid clock-boundary issues. The private key is exported in an encrypted PFX; the public certificate is exported as a CER. The output filenames use the certificate thumbprint.

The PFX password is prompted for unless -GeneratedPfxPassword or -CertificatePasswordEnvironmentVariable supplies it. Empty passwords are rejected. Without -ProvisionEntraApp, generation stops after reporting the certificate paths and thumbprint. This mode is useful when an administrator will configure an Entra app separately.

2. Generate and provision an Entra app

Add -ProvisionEntraApp to generation for interactive, one-time setup. The script signs in to Microsoft Graph using device-code authentication in the specified tenant. It then creates or reuses a single-tenant application with the requested display name, uploads the public certificate, configures the required Microsoft Graph application permissions, creates or reuses the app's service principal, grants those application roles, assigns the Teams Administrator directory role at tenant scope, and saves a connection profile.

The administrator signing in must be able to grant the application consent and assign directory roles, such as a Privileged Role Administrator or Global Administrator. The script requests these delegated setup scopes:

  • Application.ReadWrite.All
  • AppRoleAssignment.ReadWrite.All
  • RoleManagement.ReadWrite.Directory

The provisioned app receives these Microsoft Graph application permissions:

  • Organization.Read.All
  • User.Read.All
  • Group.ReadWrite.All
  • AppCatalog.ReadWrite.All
  • TeamSettings.ReadWrite.All
  • Channel.Delete.All
  • ChannelSettings.ReadWrite.All
  • ChannelMember.ReadWrite.All

The combination with the tenant-wide Teams Administrator role is powerful. It allows broad Teams administration and write operations involving groups, Teams, channels, and the app catalog. Review the permission set and tenant policy before provisioning. This script does not add Directory.ReadWrite.All or Skype and Teams Tenant Admin API permissions.

If an application with the same display name already exists, the script reuses it; multiple exact-name matches are an error. Existing application permissions and certificate credentials are retained while the required permissions and generated certificate are added or updated. If Graph does not return enough public-key information to safely retain existing credentials, provisioning stops rather than removing them. Role and permission changes can take time to replicate, so connect from a fresh PowerShell session after provisioning.

3. Connect using a saved profile

-UseCertificateAuth selects a saved profile, resolves its PFX path, prompts for the PFX password, validates the certificate, imports MicrosoftTeams if needed, and calls Connect-MicrosoftTeams with the tenant, application ID, and loaded certificate object. The script leaves the successful Teams connection open for subsequent commands in that session.

4. Connect using an existing app and PFX

An existing Entra application can be used without provisioning. Supply the tenant, app ID, and PFX path explicitly. A profile can also be used, with explicit values overriding corresponding profile values. Windows profiles that contain only a certificate thumbprint are insufficient on Linux; provide an exported PFX using -CertificateFilePath.

Storage and Profile Behavior

By default, certificate files are stored in:

$XDG_DATA_HOME/ciaops/tms, or ~/.local/share/ciaops/tms when XDG_DATA_HOME is unset or not an absolute path.

The JSON profile map is stored in:

$XDG_CONFIG_HOME/ciaops/tms/o365-tms-cert-auth.json, or ~/.config/ciaops/tms/o365-tms-cert-auth.json when XDG_CONFIG_HOME is unset or not an absolute path.

The profile map can be either a JSON array or an object with a profiles array. Each saved profile records its name, tenant/organization, app ID, certificate thumbprint, and PFX path. It never stores the PFX password. When a profile contains a relative PFX path, the script resolves it relative to the profile map's directory. Saving a profile replaces an entry with the same app ID and profile name; other entries are retained.

The script restricts storage directories to owner-only mode 700 and files to owner read/write mode 600, independent of the user's umask. This includes custom output and profile-map directories, which must therefore be dedicated to this script. Symbolic links in storage paths are rejected. The profile map is written through a temporary file and moved into place while holding a lock file to avoid concurrent updates colliding.

For an existing PFX, the script rejects symbolic links and any file whose permissions grant access beyond the owner; set its mode to 600 before connecting. It imports the private key with an ephemeral key-storage flag, avoiding persistent installation into a system certificate store.

Parameters

Parameter Purpose
-GenerateLocalCertificate Generate a certificate and encrypted PFX.
-UseCertificateAuth Connect to Teams with a certificate. Exactly one of this and generation must be selected.
-GeneratedCertSubject Certificate common name and default app display name; defaults to O365-TMS-AppAuth.
-GeneratedCertYearsValid Certificate lifetime in years, from 1 through 100; defaults to 2.
-GeneratedCertOutputPath Certificate directory; defaults to the XDG data directory above.
-GeneratedPfxPassword SecureString password for a generated PFX.
-ProvisionEntraApp During generation, interactively configure the Entra app, permissions, role, and profile. Requires -Tenant; cannot be combined with headless mode.
-AppDisplayName Provisioned app display name; defaults to -GeneratedCertSubject. Duplicate exact matches are rejected.
-SetupClientId Optional tenant-approved public client ID used for Graph device-code sign-in.
-UseCertificateAuth inputs: -Tenant, -AppId, -CertificateFilePath Explicit connection values. All three are needed when not resolved from a profile. -Organization is an alias for -Tenant.
-ProfileName Name of the saved profile to select. A unique match is required after applying any tenant filter.
-CertificateMapPath Path to the JSON profile map. Defaults to the XDG config path above.
-CertificatePassword SecureString password for the PFX used during connection.
-CertificatePasswordEnvironmentVariable Process environment variable name from which to read a PFX password when the relevant SecureString parameter is omitted.
-CertificateThumbprint Optional expected thumbprint; also read from a profile and compared with the imported PFX.
-Headless / -noprompt Disable prompts. Requires supplied passwords and preinstalled modules; skips the module update check and is not allowed for provisioning.
-noupdate Skip the MicrosoftTeams Gallery version check.
-enableLog Write a transcript under the private data directory. Provisioning logs may contain short-lived device codes.

Use Get-Help ./o365-connect-tms-cert-linux.ps1 -Full for PowerShell's parameter help.

Examples

Provision an app and profile

./o365-connect-tms-cert-linux.ps1 -GenerateLocalCertificate -ProvisionEntraApp -Tenant contoso.onmicrosoft.com

The script prompts for a PFX password, then starts device-code sign-in for an administrator. The resulting profile defaults to the app display name.

Connect from a saved profile

./o365-connect-tms-cert-linux.ps1 -UseCertificateAuth -ProfileName O365-TMS-AppAuth
Get-CsTenant

The password is prompted for by default. Run the Teams command in the same PowerShell session as the connection.

Connect to an existing app without a profile

./o365-connect-tms-cert-linux.ps1 `
  -UseCertificateAuth `
  -Tenant contoso.onmicrosoft.com `
  -AppId 11111111-2222-3333-4444-555555555555 `
  -CertificateFilePath /home/admin/auth.pfx `
  -CertificatePassword $vaultPassword `
  -noupdate

Ensure the PFX is owner-only (chmod 600) and pass a SecureString obtained from a secret vault where possible.

Headless connection with an injected secret

./o365-connect-tms-cert-linux.ps1 `
  -UseCertificateAuth `
  -ProfileName O365-TMS-AppAuth `
  -Headless `
  -noupdate `
  -CertificatePasswordEnvironmentVariable TMS_PFX_PASSWORD

The environment variable must be populated by the scheduler or secret manager before starting the script. The script reads it from the current process, converts it to a SecureString in memory, and does not print or save the password. Other processes running as the same user may be able to access process environment values, so a vault-supplied SecureString is preferable.

Validation Before Connecting

Before importing MicrosoftTeams, the script:

  1. Requires a tenant, app ID, and PFX path, resolved either explicitly or from exactly one matching profile.
  2. Requires an owner-only, non-symbolic-link PFX and a nonempty password.
  3. Confirms the PFX contains a private key.
  4. Compares the certificate thumbprint with the optional/profile expectation.
  5. Checks that the certificate is currently valid and warns if it expires in fewer than 30 days.

It then imports MicrosoftTeams version 5.0.0 or later and connects with Connect-MicrosoftTeams -TenantId ... -ApplicationId ... -Certificate .... If connection fails, the imported certificate object is disposed. On success, it is retained for the live Teams session because the module may need it for token renewal.

Prompts, Logging, and Operational Safety

  • -Headless (alias -noprompt) disables prompts. Supply the relevant password by SecureString or environment-variable name, and install required modules in advance. Headless mode also skips the Teams Gallery update check.
  • Without -noupdate, an interactive connection checks the Gallery for a newer MicrosoftTeams version when an acceptable version is already installed. A failed update check is a warning; accepting an available update installs it for the current user.
  • -enableLog creates a transcript in the private data directory. Treat the transcript as sensitive: during provisioning it may capture a temporary device code. Protect and remove logs according to local policy.
  • Keep PFX files and passwords separately protected. The PFX is encrypted, but its file permissions and password handling still matter.
  • The script does not disconnect Teams after a successful connection. Close the PowerShell process to end that session.

Limitations

Application authentication is not supported by every Teams PowerShell cmdlet. Administrative Unit scenarios may need permissions not granted by this script. Consult Microsoft's Teams PowerShell application authentication documentation for current cmdlet support and requirements.

This script is provided as-is, without warranty. Review the requested permissions and certificate lifecycle before using it in production.

Clone this wiki locally