Identity is the new security perimeter. In the cloud, your identity system is more important than your firewall. Master Azure Active Directory (Azure AD) and you master Azure security.
Step 1: Identity (Prove who you are)├── Show your employee badge (authentication)├── Security guard checks photo matches your face└── Badge has your name and employee IDStep 2: Access (What can you do)├── Badge gives access to certain floors only├── Your floor: Marketing (5th floor) ✅├── Other floors: Engineering (3rd floor) ❌├── CEO's office: ❌ (even though you're on same floor)└── Conference rooms: ✅ (shared access)Result:- You proved WHO you are (identity)- System knows WHAT you can access (permissions)
This is exactly how Azure IAM works:
Your username/password = Employee badge (proves identity)
Your Company Network (The Castle):├── Firewall (The Moat) → Strong perimeter defense├── Inside the network → Everyone trusted└── Outside the network → Everyone blockedProblem:- Once attacker gets inside → They have access to everything- Employees work from home → How do they get "inside"?- SaaS apps (Office 365, Salesforce) → Outside your network!
Modern Security Model (2025): Zero Trust
Assume NOTHING is trusted:├── Inside network ≠ Trusted├── Every request requires authentication├── Every action requires authorization└── Identity is the new perimeterResult:- Attacker steals one password → Only accesses what that user can access- Employee works from home → Uses identity to access (no VPN needed)- SaaS apps → Use identity federation (single sign-on)
Why This Matters:
In the cloud, there is NO “inside” or “outside” network. Your app might run in Azure, your data might be in Office 365, your users might be anywhere in the world. Identity is the ONLY way to control access.
Authentication vs Authorization (The Most Confused Concepts)
People mix these up constantly. Here’s the clear difference:Authentication = Proving WHO you are
Question: "Are you really Alice?"Methods:- Password: Something you know- Phone code: Something you have- Fingerprint: Something you areResult: Yes, you are Alice ✅
Authorization = What are you ALLOWED to do
Question: "What can Alice do?"Check permissions:- Can Alice read this file? ✅- Can Alice delete this database? ❌- Can Alice create VMs? ✅Result: Alice can do X, Y, Z but not A, B, C
You walk into a bankBank teller asks:1. "What's your account number?" (something you know)2. "Show me your driver's license" (something you have)3. "Sign here" (something you are - handwriting)You prove you ARE account holder #12345 ✅
Authorization (What you can do):
Now that bank knows you're account holder #12345:- Withdraw from YOUR account: ✅- Withdraw from SOMEONE ELSE'S account: ❌- Access YOUR safe deposit box: ✅- Access the bank vault: ❌Your identity determines your permissions
In Azure:Authentication:
User: alice@company.comPassword: ********MFA code from phone: 123456Azure AD verifies: Yes, this is Alice ✅
Authorization (RBAC):
Check what Alice can do:- Read resources in resource group "dev": ✅- Create VMs in resource group "dev": ✅- Delete resources in resource group "prod": ❌- Read billing information: ❌Azure RBAC enforces these permissions
Scenario: Company with 100 employees using AzureWithout Proper IAM (Chaos):
Problems:1. Everyone shares one admin password - Password leaked → Everyone compromised - Someone leaves company → Must change password for everyone2. No audit trail - Database deleted → Who did it? No idea - Compliance audit → Can't prove who accessed what3. Too much access - Junior dev has same access as CTO - Intern can delete production database - Contractor can see payroll data4. Manual management - New employee → Manually grant 20 permissions - Employee changes role → Manually update permissions - Employee leaves → Manually revoke access (if you remember!)Result: Security nightmare, compliance failure, eventual data breach
With Proper IAM (Controlled):
Solutions:1. Each person has unique identity - alice@company.com (Developer) - bob@company.com (DBA) - charlie@company.com (Intern) - Password leaked → Only one account compromised2. Complete audit trail - Database deleted → Logs show: bob@company.com at 2:45 PM - Compliance audit → Full report of who accessed what and when3. Principle of least privilege - Developers: Can deploy to dev environment ✅ - Developers: Cannot access production ❌ - DBAs: Can access databases ✅ - DBAs: Cannot create VMs ❌ - Interns: Read-only access to dev ✅4. Automated management - New employee → Assign to "Developers" group → Auto-gets all permissions - Role change → Change group membership → Permissions auto-update - Employee leaves → Disable account → All access revoked instantlyResult: Secure, compliant, auditable, scalable
What Happened:- Former employee had excessive permissions- Used those permissions to access 100 million customer records- Downloaded credit card applications, social security numbersRoot Cause:- Overly permissive IAM policies- No principle of least privilege- Poor access review processesCost:- $80 million fine from regulators- $190 million settlement to customers- Reputation damage (priceless)Total: $270+ millionPrevention Cost:- Proper IAM implementation: ~$100,000- Regular access reviews: ~$20,000/year- ROI: 2,700x return on investment (preventing $270M loss)
Every IAM system answers these questions:1. Who are you? (Authentication)
Methods:- Username + Password (something you know)- MFA code from phone (something you have)- Biometric (something you are)- Certificate (something you possess)Result: Identity verified ✅
2. What can you do? (Authorization)
Permissions:- Role: Developer- Resources: resource-group-dev- Actions: Can create, read, update (not delete)Result: Permissions defined ✅
3. Are you still allowed? (Conditional Access)
Checks:- Is your device managed? ✅- Are you in a trusted location? ✅- Is it normal hours? ✅- Is there suspicious activity? ❌ → BlockResult: Access granted or denied based on context
4. What did you do? (Auditing)
Logs:- alice@company.com- Created VM "web-server-01"- In resource group "production"- At 2024-01-22 14:32:05 UTC- From IP: 203.0.113.42Result: Complete audit trail ✅
Bad:- Team shares "admin@company.com" account- Everyone knows the passwordWhy bad:- No accountability (who made that change?)- One compromise = everyone compromised- Can't revoke access for one person
✅ Correct: Each person has unique identity❌ Mistake 2: Giving everyone admin rights
Bad:- "Making someone admin is easier than figuring out exact permissions"- Everyone is Owner on everythingWhy bad:- Intern can delete production- Contractor can see payroll- Huge blast radius when account compromised
✅ Correct: Principle of least privilege (minimum permissions needed)❌ Mistake 3: Never reviewing access
Bad:- Grant permissions when needed- Never remove them- People accumulate permissions over yearsResult:- Former employee still has access (left 2 years ago!)- Person changed roles but kept old permissions- Service accounts no longer used but still active
✅ Correct: Regular access reviews (quarterly/annually)❌ Mistake 4: No MFA
Bad:- "Passwords are enough"- "MFA is annoying"Reality:- 99.9% of account compromises use stolen passwords- MFA blocks these attacks
✅ Correct: Require MFA for all users (especially admins)Cost Tip: MFA is essentially free. Azure AD Free tier includes Security Defaults, which enforces MFA for all users at no additional cost. You only pay for Azure AD Premium (6−9/user/month) if you need Conditional Access policies (e.g., “require MFA only from untrusted locations” or “block access from unmanaged devices”). For most small teams, Security Defaults provides excellent protection at zero cost — and it is the single highest-ROI security measure you can implement.
Question 1: What type of identity?├─ Human user → Continue to Question 2└─ Application/Service → Use Managed Identity or Service Principal (Never use shared passwords for service-to-service auth. Managed Identities are free and eliminate credential rotation entirely.)Question 2: How sensitive is the access?├─ Admin access → Require MFA + Conditional Access + PIM (just-in-time elevation)├─ Regular access → Require MFA└─ Read-only public data → Password only (acceptable)Question 3: What authentication method?├─ Passwordless options (RECOMMENDED):│ ├─ Windows Hello for Business (biometric) -- Best for corporate Windows devices│ ├─ FIDO2 security keys (hardware token) -- Best for shared workstations, high-security│ └─ Microsoft Authenticator (push notification) -- Best for mobile workforce, BYOD│└─ Password + MFA: ├─ Authenticator app (best) ├─ SMS/Phone call (better than nothing) └─ Hardware token (most secure)Question 4: Do you need conditional access?├─ Require managed devices? → Azure AD Premium P1├─ Require specific locations? → Azure AD Premium P1├─ Block risky sign-ins? → Azure AD Premium P2└─ Basic MFA only → Azure AD Free
Azure Active Directory (Azure AD) is Microsoft’s cloud-based identity and access management service. It’s NOT the same as on-premises Active Directory.
Common Mistake: Trying to use Azure AD like on-premises ADAzure AD is designed for modern authentication:
No LDAP queries (use Microsoft Graph API)
Different mindset: API-first, cloud-first
[!TIP]
Jargon Alert: Service Principal
Think of a Service Principal as a “user account for an application.” Just like you have a username/password, an app needs an identity to log in.A Managed Identity is just a Service Principal that Azure creates and rotates the password for automatically. (Always use Managed Identities when possible!)
Azure AD issues three distinct types of tokens. Using the wrong one is a common security failure.
Token
Purpose
Handled By
Typical Lifetime
ID Token
Proves identity (OIDC)
Your Application
1 hour
Access Token
Authorizes access
The Resource (API)
1 hour
Refresh Token
Gets new tokens
Your Application
90 days (rolling)
[!WARNING]
Security Gotcha: ID Token vs. Access Token
Never use an ID Token to authorize API calls. ID tokens are meant for your app to know “who logged in.” Access tokens are meant for the API to know “what this user can do.” If you send an ID token to a backend, you’re bypassing authorization checks.
Both ID and Access tokens are JWT (JSON Web Tokens). They are Base64 encoded, not encrypted. Anyone who has the token can read it (using jwt.ms).Key Claims inside an Azure AD Token:
aud (Audience): The intended recipient of the token. If this doesn’t match your app/API ID, reject it.
scp (Scope): The permissions granted (e.g., User.Read).
roles: The RBAC roles assigned to the user.
exp (Expiry): When the token dies.
nonce: Prevents replay attacks (essential for security).
[!TIP]
Pro Tip: Managed Identities
If your application runs inside Azure (e.g., on a VM or App Service), use Managed Identities. You don’t have to manage client_id or client_secret variables. Azure handles the token exchange securely in the background, eliminating the risk of leaking secrets in your code.
Don’t require MFA for everyone, everywhere. Use Conditional Access for smart MFA:
Policy: Smart MFAConditions: - User is NOT on corporate network - User accessing from unknown device - Sign-in risk: Medium or HighActions: - Require MFA - Require compliant device
Real-World Example:
Scenario 1: Office NetworkUser: alice@company.comLocation: Corporate network (trusted IP)Device: Company laptop (Intune-managed)Action: ✅ No MFA required (trusted environment)Scenario 2: Home NetworkUser: alice@company.comLocation: Home (untrusted)Device: Personal laptopAction: ⚠️ Require MFAScenario 3: Coffee ShopUser: alice@company.comLocation: Public WiFi (untrusted)Device: Personal phoneRisk: High (Azure AD detects anomaly)Action: ❌ Block access OR require re-authentication + MFA
Who (Security Principal) + What (Role) + Where (Scope) = Permission
[!WARNING]
Gotcha: RBAC Propagation Delay
After assigning an RBAC role, it can take up to 30 minutes for permissions to propagate across all Azure regions. If a user says “I still can’t access it,” they might just need to wait a few minutes and refresh their token (re-login).
Management Group (org-wide policies) ↓ inheritsSubscription (billing boundary) ↓ inheritsResource Group (lifecycle boundary) ↓ inheritsResource (individual service)
Inheritance Rules:
Permissions accumulate downward
Child inherits parent permissions
Cannot remove inherited permissions (only add)
Explicit Deny doesn’t exist in Azure RBAC (unlike AWS)
Example:
# Alice has these assignments:# 1. Reader at Subscription level# 2. Contributor at "Dev" Resource Group# Effective permissions:Subscription scope: ✅ Can view all resources ❌ Cannot modify anythingDev Resource Group: ✅ Can view AND modify resources ✅ Can create new resources ❌ Cannot assign roles (not Owner)✅ Can view resources (inherited from Subscription) ❌ Cannot modify (no Contributor role)
While RBAC is great for 90% of scenarios, large-scale enterprises often hit a “Role Explosion” problem—creating hundreds of custom roles for every tiny variation. This is where Attribute-Based Access Control (ABAC) comes in.
How ABAC Works in Azure (Role Assignment Conditions)
In Azure, ABAC is implemented as conditions added to a standard Role Assignment.Example Scenario:
You want to allow developers to delete blobs in Storage, but ONLY if the blob has a tag Project=Phoenix.RBAC Way: Create a custom role for Project Phoenix? No, that’s brittle.
ABAC Way:
Assign Storage Blob Data Contributor to the Developer group.
Add an ABAC Condition: (Target Resource Tag 'Project' EQUAL TO 'Phoenix')
[!IMPORTANT]
Pro Tip: ABAC for Dev/Test
ABAC is extremely powerful for “Sandboxing.” You can grant a user Contributor access to a whole subscription, but add an ABAC condition that they can only modify resources with a tag matching their own Username. This creates a “dynamic sandbox” without managing thousands of separate resource groups.
Name: Require MFA for All UsersConditions: - Users: All users - Cloud apps: All cloud appsGrant: - Require MFAState: Enabled (Report-only first, then enforce)
Why: Passwords are compromised daily. MFA blocks 99.9% of automated attacks.Exceptions: Service accounts (use managed identities instead)
Policy 2: Block Legacy Authentication
Critical security policy
Name: Block Legacy AuthenticationConditions: - Users: All users - Cloud apps: All cloud apps - Client apps: Exchange ActiveSync, Other clientsGrant: - Block accessState: Enabled
Why: Legacy protocols (POP, IMAP, SMTP) don’t support MFA. Used in 97% of credential attacks.Before enabling: Audit sign-in logs to ensure no legitimate legacy auth usage
Policy 3: Require Compliant Device for Admins
Protect privileged accounts
Name: Admins Require Compliant DeviceConditions: - Users: All admin roles - Cloud apps: Azure portal, Microsoft 365 adminGrant: - Require device to be marked as compliant - Require MFA - Require all selected controlsState: Enabled
Why: Admin accounts are high-value targets. Ensure they’re only accessed from managed devices.Requires: Microsoft Intune (device management)
Policy 4: Block Access from Unknown Locations
Geo-based restrictions
Name: Block Access from High-Risk CountriesConditions: - Users: All users (except break-glass accounts) - Cloud apps: All cloud apps - Locations: Countries where company doesn't operateGrant: - Block accessState: Enabled (after VPN solution for travelers)
Why: If you don’t have employees in certain countries, block them entirely.Caution: Legitimate users traveling? Provide VPN that routes through approved locations.
Policy 5: Require MFA for Azure Management
Protect infrastructure access
Name: Azure Management Requires MFAConditions: - Users: All users - Cloud apps: Microsoft Azure ManagementGrant: - Require MFAState: Enabled
Why: Azure portal, CLI, PowerShell access should always require MFA.Scope: Applies to portal, Azure CLI, PowerShell, APIs
Alice: Owner role on Production subscription (permanent)Risks:- Alice's account compromised → attacker has Owner access- Alice doesn't need Owner 99% of the time- Can accidentally delete resources- No approval workflow- Hard to audit (always elevated)Blast radius: MAXIMUM
Just-in-time admin access
Alice: Eligible for Owner role (not active)When Alice needs elevated access:1. Requests activation (via portal/API)2. Provides justification: "Deploy hotfix for incident #12345"3. Optional: Approval from manager4. Elevated to Owner for 4 hours (configurable)5. All actions logged6. Auto-demoted after 4 hoursBenefits:✅ Reduced attack surface (not always admin)✅ Auditable (who elevated when and why)✅ Time-limited (automatic expiration)✅ Approval workflow (for sensitive roles)Blast radius: MINIMAL (only when elevated)
# Instead of assigning role permanently:az role assignment create \ --assignee alice@company.com \ --role Owner \ --scope /subscriptions/{sub-id}# Make them ELIGIBLE via PIM:# (Done via Azure Portal: Azure AD > PIM > Azure Resources)
Step 2: Configure Role Settings
Role: OwnerActivation: - Maximum duration: 4 hours - Require justification: Yes - Require approval: Yes (for Owner role) - Approvers: Security team - Require MFA: YesAssignment: - Maximum eligible duration: 180 days (then re-justify) - Require justification on assignment: Yes
Step 3: User Activates Role
User: AliceRole: OwnerDuration: 4 hoursJustification: "Deploy emergency hotfix for incident INC-12345"Approval: RequiredApprover: Bob (Security Lead)Workflow:1. Alice requests activation (Portal or API)2. Bob receives notification3. Bob approves (or denies)4. Alice elevated for 4 hours5. After 4 hours: Auto-demotion6. All logged in Azure AD audit logs
Review: Owner role eligibilityScope: All users eligible for OwnerFrequency: QuarterlyReviewers: Resource ownersQuestions:1. Does this user still need this role?2. Should we reduce their maximum duration?3. Should we add more approvers?Actions:- Remove access (no longer needed)- Reduce duration (4 hours → 2 hours)- Add approval requirement
# Via Portal: Azure AD > Security > Conditional Access > New PolicyName: Require MFA for Azure PortalAssignments: Users: All users Cloud apps: Microsoft Azure ManagementAccess controls: Grant: Require MFAEnable policy: On
Policy 2: Block Legacy Authentication
Name: Block Legacy AuthenticationAssignments: Users: All users Cloud apps: All Conditions: Client apps: Exchange ActiveSync, Other clientsAccess controls: Block accessEnable policy: Report-only (test first)
The Catch-22: Be careful not to create a policy that blocks YOU from the portal. Always exclude at least one “Emergency Access” account (more on this below).
Report-Only Mode: Always test new policies in “Report-Only” mode for a week before enforcing them. Check the logs to see who would have been blocked.
Location Spoofing: Remember that VPNs and Tor can be used to bypass location-based policies. Use “Sign-in Risk” as a secondary check.
The Problem: You lost your phone, and you are the only Global Admin.
The Solution:
The Break-Glass Account: Every tenant should have 1-2 “Emergency Access” accounts that are excluded from all Conditional Access policies and have a long, complex password stored in a physical safe.
Microsoft Support: If you don’t have a break-glass account, you’ll need to call Microsoft. Prepare for a long identity verification process involving your corporate documents.
The Problem: Someone accidentally removed all “Owner” assignments from the subscription.
The Solution:
An Account Admin (the person who pays the bill) can elevate themselves to access the subscription via the Azure Enterprise Portal or by contacting support to reset the “Elevate Access” toggle in Entra ID properties.
[!CAUTION]
Warning: The “Elevate Access” Toggle
A Global Admin can toggle a setting in Entra ID to grant themselves “User Access Administrator” at the Root (/) scope. This allows them to see and fix every subscription in the tenant. This is a massive security risk and should only be used in true emergencies, then immediately toggled off and audited.
Q1: What's the difference between Azure AD and Active Directory?
Answer:Azure AD (modern, cloud-native):
Protocol: OAuth 2.0, OIDC, SAML
Structure: Flat (no OUs)
Use: Cloud apps, SaaS, Azure resources
Management: REST API, Graph API
Active Directory DS (traditional, on-premises):
Protocol: Kerberos, LDAP
Structure: Hierarchical (OUs, GPOs)
Use: Domain services, on-prem apps
Management: ADUC, Group Policy
Key Point: They serve different purposes. Azure AD is NOT a replacement for AD DS in the cloud.
Q2: Why use managed identities instead of service principals?
Answer:Managed Identities:
✅ No credentials to manage
✅ Automatic rotation by Azure
✅ Cannot be stolen from code
✅ Lifecycle tied to resource
Service Principals with Secrets:
❌ Secret stored somewhere (Key Vault, config)
❌ Must manually rotate (every 90 days)
❌ Can be leaked (Git, logs)
❌ Overhead to manage
Use Service Principal only when: Running outside Azure (on-premises, other clouds)
Q3: What is the purpose of Conditional Access?
Answer:Conditional Access enforces security controls based on context:Instead of: “All users always need MFA”
Use: “Users need MFA WHEN accessing from untrusted location OR unknown device”Benefits:
Your company has 500 engineers. Some need production access for on-call, but a developer accidentally deleted a production database. Design an access control strategy.
Strong Candidate Answer:This is fundamentally a Privileged Identity Management (PIM) problem combined with proper RBAC scoping. The goal is zero standing access to production.
Layer 1 — RBAC with least privilege: No engineer gets permanent Contributor or Owner on production resource groups. Everyone gets Reader by default on production so they can view dashboards and logs for debugging. Developer teams get Contributor only on their dev/staging subscriptions.
Layer 2 — PIM for just-in-time access: On-call engineers activate a time-limited (4-hour maximum) Contributor role on production through Azure AD PIM. This requires MFA, a justification reason, and optionally manager approval. The activation is logged and auditable. When the window expires, access is automatically revoked.
Layer 3 — Custom roles to prevent catastrophic actions: Instead of granting full Contributor, I would create a custom RBAC role called “Production Operator” that includes read/write permissions but explicitly excludes delete actions on databases and resource groups. Even with elevated access, an engineer cannot delete the database.
Layer 4 — Azure Resource Locks: Put a CanNotDelete lock on every production database and resource group. Even an Owner cannot delete a locked resource without first removing the lock, which creates a separate audit trail.
Real-world example: After implementing this pattern at a fintech company, accidental production deletions dropped from 3-4 per quarter to zero over 18 months. The PIM activation logs also satisfied SOC 2 Type II auditors.
Follow-up: An on-call engineer at 3 AM needs production access but PIM requires manager approval and the manager is asleep. How do you handle this?Configure PIM with tiered approval. For the “Production Operator” custom role, set self-approval with mandatory MFA and justification — no manager approval needed for the limited-scope role. For the full Contributor role (which includes delete permissions), require manager approval during business hours and a secondary approver (the on-call lead) for after-hours requests. The limited “Operator” role should be sufficient for 95% of on-call tasks.
Explain the difference between a Service Principal and a Managed Identity. When would you use one over the other?
Strong Candidate Answer:
Service Principal: An identity you create manually in Entra ID for applications or CI/CD pipelines. It has a client ID and either a client secret or a certificate. You are responsible for rotating the secret before it expires. If the secret leaks, an attacker can impersonate that application.
Managed Identity: An identity that Azure creates and manages automatically for Azure resources. There is no secret to manage — Azure handles credential rotation internally using the Instance Metadata Service (IMDS). The token is injected into the resource automatically.
When to use Managed Identity (always prefer this): Any Azure resource talking to another Azure resource. App Service accessing Key Vault, AKS pods reading from Blob Storage, Azure Functions writing to Cosmos DB. I use system-assigned for single-purpose resources and user-assigned when multiple resources need the same identity.
When Service Principal is unavoidable: External CI/CD systems (GitHub Actions outside Azure), third-party SaaS applications, on-premises applications connecting to Azure, and multi-tenant scenarios. The mitigation for GitHub is OIDC federation, which eliminates secrets entirely.
The security gap people miss: Service Principal secrets stored in CI/CD pipeline variables are the number one credential leak vector. I have seen GitHub Actions workflows with Azure credentials committed to public repositories.
Follow-up: A developer stored a Service Principal secret in appsettings.json and committed it to Git. What is your incident response?Immediate actions in order: (1) Revoke the secret immediately in Entra ID. (2) Generate a new secret and store it in Key Vault with reference binding. (3) Check sign-in logs for the compromised principal to detect unauthorized use. (4) Audit what RBAC roles it had — if it was Contributor on production, assume breach and check for unauthorized changes. (5) Long-term: migrate to Managed Identity or implement OIDC federation and add pre-commit scanning with gitleaks.
Design a Conditional Access policy strategy for a company with 2,000 employees across 5 countries, including contractors on personal devices.
Strong Candidate Answer:
Baseline policy (applies to everyone): Require MFA for all users on all cloud applications. No exceptions. Microsoft’s research shows MFA blocks 99.9% of account compromise attacks. Use the Authenticator push notification which takes 2 seconds.
Location-based policies: Create named locations for each office. From trusted office IPs, allow compliant devices with 12-hour session lifetime. From untrusted locations, require MFA on every sign-in with 1-hour sessions. Block sign-ins from countries where the company has no employees.
Device-based policies for contractors: Contractors on unmanaged devices get: MFA required, app-enforced restrictions (read-only in SharePoint, no downloads), 4-hour session limit, and Conditional Access App Control for inline session monitoring.
Risk-based policies: Enable Identity Protection. If Entra ID detects risky sign-in (impossible travel, anonymous IP, password spray), automatically require MFA re-authentication or block for high-risk signals. Force password reset if credentials appear in a known breach database.
The cost consideration: Conditional Access requires Entra ID P1 (6/user/month).For2,000employees,thatis12,000/month. Compared to an average breach cost of $4.45M, the ROI is clear.
Follow-up: A VIP executive refuses to use MFA. How do you handle this?I would never create an MFA exception, especially for VIPs who are the highest-value phishing targets. Instead, offer a FIDO2 security key (YubiKey) — tap the key, done in 1 second, more secure than SMS and faster than typing a password. If they refuse all second-factor methods, escalate to the CISO with a risk acceptance document the executive must personally sign. In my experience, nobody wants to sign that document.