# Sgcwebsockets Dotnet Auth

> sgcWebSockets .NET Authentication

- Skill: `esegece-com/sgcwebsockets-dotnet-auth` (Agent Skill, multi-file: 103 files)
- Install (CLI): `npx skillmds@latest add esegece-com/sgcwebsockets-dotnet-auth`
- Raw SKILL.md: https://api.skillmd.com/api/skills/esegece-com/sgcwebsockets-dotnet-auth/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: esegece-com (https://skillmd.com/u/esegece-com)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/esegece-com/sgcwebsockets-dotnet-auth

---


# sgcWebSockets .NET Authentication

Five components for proving who a caller is: OAuth2 on both sides, JWT on both
sides, and a WebAuthn passkey server.

These are the components that actually authenticate. If you are looking for a
sign-in form or a session cookie, that is your application's job; this skill is
about the tokens.

## When to use this skill

- Get an access token from an OAuth2 provider (Google, Microsoft, GitHub, Okta)
- Be the OAuth2 authorization server for your own clients
- Sign or verify a JWT
- Accept a passkey registration or assertion

## Components in this skill

| Component | Side |
| --- | --- |
| `TsgcHTTP_OAuth2_Client` | asks a provider for tokens |
| `TsgcHTTP_OAuth2_Server` | issues them |
| `TsgcHTTP_JWT_Client` | signs and sends |
| `TsgcHTTP_JWT_Server` | verifies |
| `TsgcWSAPIServer_WebAuthn` | passkey registration and assertion |

## Before you start, ask the developer

Use a structured question tool if your host has one, for example Claude Code's
`AskUserQuestion`. Otherwise ask in chat:

1. **Consuming a provider, or being one?** Client and server are different
   components and almost entirely different work.
2. **Which grant type?** Authorization code, client credentials, device code
   and password are four different flows with four different redirect stories.
   `OAuth2Options.GrantType` picks it, and it is not a detail to default.
3. **Where does the token live afterwards?** In memory, a cookie, a store. The
   component obtains it; keeping it is yours.
4. **Is there a redirect URI, and is it registered?** The most common OAuth2
   failure is a redirect URI that does not match the provider's registration
   exactly, down to the trailing slash.

## The two option objects, which is where people go wrong

`TsgcHTTP_OAuth2_Client` has both `OAuth2Options` and
`AuthorizationServerOptions`, and they hold different things:

- **`OAuth2Options`** holds who you are: `ClientId`, `ClientSecret`,
  `GrantType`, and `Username`/`Password` for the password grant.
- **`AuthorizationServerOptions`** holds where the provider is: `AuthURL`,
  `TokenURL`, `Scope`, `RevocationURL`, `IntrospectionURL` and
  `DeviceAuthorizationURL`.

Putting the client id on `AuthorizationServerOptions` compiles and fails at
runtime with an error from the provider that does not name the real problem.

```csharp
using esegece.sgcWebSockets;

var oauth = new TsgcHTTP_OAuth2_Client();
oauth.OAuth2Options.ClientId = Environment.GetEnvironmentVariable("OAUTH_ID");
oauth.OAuth2Options.ClientSecret = Environment.GetEnvironmentVariable("OAUTH_SECRET");
oauth.AuthorizationServerOptions.AuthURL = "https://provider/authorize";
oauth.AuthorizationServerOptions.TokenURL = "https://provider/token";
oauth.AuthorizationServerOptions.Scope = "openid profile";
oauth.OAuth2Options.GrantType = TsgcOAuth2GrantTypes.auth2CodePKCE;
oauth.LocalServerOptions.Port = 8080;
oauth.LocalServerOptions.RedirectURL = "http://localhost:8080/callback";

oauth.Start();
```

`LocalServerOptions` is the small local listener that receives the authorization
code redirect, which is what makes the code grant workable from a desktop
application. Its `RedirectURL` and the URI registered with the provider have to
be the same string.

The grant types are `auth2Code`, `auth2CodePKCE`, `auth2ClientCredentials`,
`auth2ResourceOwnerPassword` and `auth2DeviceCode`.

Beyond the flow itself: `Refresh(refreshToken)`, `Revoke(token, hint)` and
`Introspect(token, hint)` are the token lifecycle methods, and the
`OnAfterAccessToken` / `OnErrorAccessToken` pair is where the result arrives.

## DPoP

The client supports DPoP (RFC 9449) through `DPoPOptions`,
`GenerateDPoPKeyPair()`, `GetDPoPProof(method, url, accessToken)` and
`GetDPoPJWKThumbprint()`. Use it when the provider requires sender-constrained
tokens. It is not on by default and it is not needed for an ordinary bearer
flow.

## Things that catch people out

- Secrets in source. A client secret in a repository is a secret that has to be
  rotated. Read it from configuration or the environment, always.
- A client secret in a desktop or mobile application is not secret at all,
  whatever the provider's console calls it. Use `auth2CodePKCE` for a
  public client.
- The redirect URI must match the registration character for character. Http
  against https, a port, a trailing slash: any of them fails, and the provider's
  error message rarely says which.
- Errors arrive on events, not as exceptions. `OnErrorAccessToken` and its
  siblings are where a rejected grant shows up, and code that only wires the
  `OnAfter*` events sees silence instead of a failure.
- The JWT components sign and verify. They do not decide what a valid token is
  allowed to do; authorisation is still yours to write.
- WebAuthn needs a secure context in the browser, so localhost or HTTPS. It
  simply will not run otherwise, and that is a browser rule, not a component
  limitation.

## Routing

- **API detail**: `reference/api/<Component>.md` has the properties, events and methods, each with its C# signature.
- **Option / enum / delegate types**: property and event types link to `reference/types/<TypeName>.md`.
- **Examples**: `examples/<Component>.md` is a trimmed snippet from the shipped demo; `examples/index.md` maps every component to its demo.
- **Getting started**: `concepts/overview.md` covers the single `using`, the target frameworks and the naming.

## What is documented

Public instance properties, events and methods declared anywhere in the
library's own class chain. Members inherited from the .NET base classes are
left out, as are internals, so a page shows the surface a caller writes
against and nothing else.

If a component you need is not here, read `concepts/coverage.md` in the
`sgcwebsockets-dotnet` skill before assuming a different name for it.
This assembly carries fewer components than the Delphi library, and saying
so is more useful than guessing an API that does not exist.

