You're staring at an event log, a WinRM trace, or an IIS 500, and the only clue is 0xC0020042. Maybe with the friendlier wrapper RPC_NT_NO_CONTEXT_AVAILABLE. The message under it reads: "No security context is available to allow impersonation."
What's actually happening here is that a worker thread called something like RpcImpersonateClient or ImpersonateLoggedOnUser, and the RPC runtime looked at that thread's token, found no client security context attached, and refused. The thread has a primary token but no impersonation token. Those are different things, and Windows is strict about the difference.
This isn't a permissions bug. It's a sequencing bug. The context is supposed to be established by the transport (named pipe, ALPC, TCP) before any code tries to impersonate. When it's missing, the caller either used the wrong binding, or it's running on a thread the RPC runtime didn't hand a context to. Here's how to narrow it down without guessing.
Fix 1: The 30-second check — are you impersonating outside the RPC call?
Nine times out of ten in custom code, someone has a helper that calls ImpersonateLoggedOnUser inside a worker thread spawned from an RPC callback. The callback thread has a context. The spawned thread does not. RPC contexts are per-thread, and they don't flow to threads you create with CreateThread.
If that's your code, stop impersonating in the worker. Do the impersonation in the callback, capture the token with OpenThreadToken and a duplicated handle, then pass the handle to the worker and call ImpersonateLoggedOnUser there. That sequence works because you're carrying the impersonation token explicitly instead of hoping the thread inherits something it won't.
HANDLE hTok = NULL;
if (!OpenThreadToken(GetCurrentThread(), TOKEN_DUPLICATE | TOKEN_IMPERSONATE, TRUE, &hTok)) {
// error 1008 here is normal on a thread with no impersonation
}
// duplicate before handing off — the original dies with the callback
DuplicateTokenEx(hTok, TOKEN_ALL_ACCESS, NULL, SecurityImpersonation, TokenImpersonation, &hDup);
CloseHandle(hTok);
// pass hDup to the worker, then ImpersonateLoggedOnUser(hDup)
If you're not writing code — if this is a Windows service or a Microsoft product — skip to Fix 2. The rest of this article assumes the code path is fine and the environment is the problem.
Fix 2: The 5-minute fix — check the binding and the service identity
The RPC context comes from the transport's authentication. If the binding handle used an unauthenticated protocol sequence, there's no context to hand you. This is common when someone configures WinRM to use a custom listener or when a DCOM object is bound with RPC_C_AUTHN_LEVEL_NONE.
For WinRM specifically, the error shows up in the Microsoft-Windows-WinRM/Operational log when a client connects over an HTTP listener that isn't backed by a valid SPN. The fix isn't in the client — it's in the listener's Kerberos setup.
Check these, in order:
- Run
winrm enumerate winrm/config/listener. Confirm the listener has a Hostname set and that hostname resolves to the machine's actual FQDN, not an alias. A CNAME-only registration is the classic cause of0xC0020042during WinRM double-hop. - Verify the SPN. Run
setspn -L <serviceaccount>. You needWSMAN/<fqdn>andWSMAN/<netbios>on the account running WinRM. If they're registered on the wrong account (often the computer account instead of the service account), Kerberos can't build a context and RPC returns no-context. - Check the service logon account. If WinRM runs as NetworkService, the SPN must be on the computer account. If it runs as a domain user, it goes on that user. Mixed up? You'll get this exact error on the second hop.
The reason step 3 works is that RPC gets its context from SSPI, SSPI needs a ticket, and a ticket needs an SPN that matches the account actually running the service. Get the SPN wrong and SSPI hands back an empty context instead of failing loudly earlier.
If you're on IIS rather than WinRM, the equivalent check is the application pool identity against the virtual directory's authentication settings. An app pool running as ApplicationPoolIdentity with Windows Authentication enabled and useAppPoolCredentials=false will impersonate the authenticated user — usually fine. Set useAppPoolCredentials=true without a matching SPN on the pool identity, and you're back to 0xC0020042 on every request.
Fix 3: The 15-minute fix — Kerberos delegation is broken
If Fix 1 and Fix 2 didn't move the needle, you're almost certainly dealing with a double-hop scenario where the second hop needs constrained delegation and doesn't have it. The pattern is familiar: client → web server → SQL server (or file share, or second RPC service). First hop authenticates fine. Second hop returns 0xC0020042 because the web server has a primary token for the user but no ticket to forward.
Unconstrained delegation "fixes" this and you should not do it. It's a security disaster. Use constrained delegation with protocol transition, or switch to a resource-based approach.
Constrained delegation setup, the parts that matter:
- Confirm the front-end service account has an SPN. Delegation only works when the first hop can be uniquely identified. Run
setspn -L <frontend-svc>. No SPN, no delegation, no context. - Set the delegation flags on the account. In ADUC, on the front-end service account's Delegation tab, choose "Trust this user for delegation to specified services only" and "Use any authentication protocol." The second option is what lets protocol transition work for users who authenticated with NTLM.
- Add the SPN of the back-end service to the list. Not the account name — the SPN. For SQL, that's
MSSQLSvc/sql01.contoso.com:1433. For a file server,cifs/fs01.contoso.com. Typos here are the #1 cause of "I set up delegation and it still fails." - If the front end is behind a load balancer, stop. Kerberos doesn't survive most LB setups without a service account per node and matching SPNs. If you can't do that, use resource-based constrained delegation on the back end instead: grant the front-end computer account
AllowedToActrights on the back-end target withSet-ADComputer -PrincipalsAllowedToDelegateToAccount.
One more thing people miss: the user account itself can be marked "Account is sensitive and cannot be delegated" (in ADUC, Account tab). If that flag is set, no amount of delegation config on the service side will help. You'll get 0xC0020042 and a KDC event on the domain controller. Check the user before you rebuild your service config.
If you're still stuck
Turn on RPC ETW tracing and look at which binding handle produced the failure. The trace will show the protocol sequence and the authn level on the failing call — that tells you whether the context was never established (transport problem, Fix 2) or was established and lost (threading problem, Fix 1).
logman create trace RpcTrace -p Microsoft-Windows-RPC -o rpc.etl -ets
# reproduce the failure
logman stop RpcTrace -ets
# open rpc.etl in Windows Performance Analyzer or netsh trace convert
The one thing I'd tell you not to do: don't chase this as a DCOM permission problem. DCOM config errors give you 0x80070005 (access denied), not 0xC0020042. If you're editing DCOM launch permissions, you're on the wrong path. The error is specifically about a missing security context on a thread, and that comes from authentication and delegation, not from ACLs.
One practical detail: on Windows Server 2019 and 2022, WinRM auto-configures the listener SPN under the computer account even when you've moved the service to a domain user. Run setspn -X to check for duplicates. A duplicate SPN silently breaks Kerberos and produces exactly this error on the first authenticated call.