diff --git a/apps/docs/components/framework_selector.tsx b/apps/docs/components/framework_selector.tsx index fca729894..814c0dcbc 100644 --- a/apps/docs/components/framework_selector.tsx +++ b/apps/docs/components/framework_selector.tsx @@ -4,8 +4,8 @@ import { useSearchParams } from 'next/navigation'; import { Tabs } from 'fumadocs-ui/components/tabs'; import { ReactNode, Suspense, useMemo } from 'react'; -const FRAMEWORKS = ['angular', 'astro', 'django', 'expressjs', 'fastapi', 'fastify', 'flask', 'flutter', 'go', 'hono', 'laravel', 'nestjs', 'nextjs', 'nuxt', 'qwik', 'react', 'solidstart', 'spring', 'symfony', 'svelte', 'vue']; -const DISPLAY_NAMES = ['Angular', 'Astro', 'Django', 'Express.js', 'FastAPI', 'Fastify', 'Flask', 'Flutter', 'Go', 'Hono', 'Laravel', 'NestJS', 'Next.js', 'Nuxt', 'Qwik', 'React', 'SolidStart', 'Spring', 'Symfony', 'Svelte', 'Vue.js']; +const FRAMEWORKS = ['angular', 'dotnet', 'astro', 'django', 'expressjs', 'fastapi', 'fastify', 'flask', 'flutter', 'go', 'hono', 'laravel', 'nestjs', 'nextjs', 'nuxt', 'qwik', 'react', 'solidstart', 'spring', 'symfony', 'svelte', 'vue']; +const DISPLAY_NAMES = ['Angular', 'ASP.NET Core', 'Astro', 'Django', 'Express.js', 'FastAPI', 'Fastify', 'Flask', 'Flutter', 'Go', 'Hono', 'Laravel', 'NestJS', 'Next.js', 'Nuxt', 'Qwik', 'React', 'SolidStart', 'Spring', 'Symfony', 'Svelte', 'Vue.js']; function FrameworkSelectorInner({ children }: { children: ReactNode }) { const searchParams = useSearchParams(); diff --git a/apps/docs/content/guides/start/quickstart.mdx b/apps/docs/content/guides/start/quickstart.mdx index 8bdc2de8d..9869d45d7 100644 --- a/apps/docs/content/guides/start/quickstart.mdx +++ b/apps/docs/content/guides/start/quickstart.mdx @@ -83,6 +83,12 @@ ZITADEL automatically configures the best security settings for your selected fr postLogoutRedirectUrl="http://localhost:3000/api/auth/logout/callback"> + + + + + + + @@ -292,6 +301,9 @@ ZITADEL handles the complexity of the OIDC handshake so your app stays secure wi - [Node.js](https://nodejs.org/) - [npm](https://www.npmjs.com/) + + - [.NET SDK 8 or later](https://dotnet.microsoft.com/download) + - [Python](https://www.python.org/) - [Poetry](https://python-poetry.org/) @@ -383,6 +395,12 @@ ZITADEL handles the complexity of the OIDC handshake so your app stays secure wi cd example-auth-astro ``` + + ```bash + git clone https://github.com/zitadel/example-auth-dotnet.git + cd example-auth-dotnet + ``` + ```bash git clone https://github.com/zitadel/example-auth-django.git @@ -534,6 +552,19 @@ ZITADEL handles the complexity of the OIDC handshake so your app stays secure wi NEXTAUTH_URL="http://localhost:3000" ``` + + 1. Copy+paste the .env.example to .env + 2. Update the ZITADEL_CLIENT_ID, ZITADEL_CLIENT_SECRET and ZITADEL_DOMAIN with the client id and issuer you collected in Step 5. + + ```bash + PORT=3000 + SESSION_DURATION=3600 + ZITADEL_DOMAIN="https://your-zitadel-domain" + ZITADEL_CLIENT_ID="your-zitadel-application-client-id" + ZITADEL_CLIENT_SECRET="your-randomly-generated-client-secret" + ZITADEL_POST_LOGOUT_URL="http://localhost:3000/auth/logout/callback" + ``` + 1. Copy+paste the .env.example to .env 2. Update the ZITADEL_CLIENT_ID and ZITADEL_DOMAIN with the client id and issuer you collected in Step 5. @@ -854,6 +885,14 @@ ZITADEL handles the complexity of the OIDC handshake so your app stays secure wi ![Astro Example App](../../../public/img/guides/quickstart/astro_example_app.png) + + ```bash + make start + ``` + + Your app will be live at `http://localhost:3000`. + + ```bash make start diff --git a/apps/docs/content/sdk-examples/dotnet.mdx b/apps/docs/content/sdk-examples/dotnet.mdx new file mode 100644 index 000000000..52fcd9a68 --- /dev/null +++ b/apps/docs/content/sdk-examples/dotnet.mdx @@ -0,0 +1,78 @@ +--- +title: ASP.NET Core +sidebar_label: ASP.NET Core +framework_url: https://learn.microsoft.com/aspnet/core/ +auth_library: "Microsoft.AspNetCore.Authentication.OpenIdConnect" +auth_library_url: https://learn.microsoft.com/aspnet/core/security/authentication/openid-connect +example_repo: https://github.com/zitadel/example-auth-dotnet +auth_flow: pkce +status: stable +--- + +## Overview + +[ASP.NET Core](https://learn.microsoft.com/aspnet/core/) is a production-ready framework for building web applications. This example integrates **Zitadel** with the built-in **OpenID Connect handler** using the **Authorization Code Flow + PKCE** to authenticate users securely and manage sessions. + +#### Auth library + +This example uses **[Microsoft.AspNetCore.Authentication.OpenIdConnect](https://learn.microsoft.com/aspnet/core/security/authentication/openid-connect)**. The middleware handles the PKCE dance, exchanges authorization codes for tokens, keeps tokens available on the request, and plugs into the standard ASP.NET Core authentication/authorization pipeline. + +--- + +## What this example demonstrates + +- Public landing page with “Sign in with Zitadel”. +- PKCE login handled by the ASP.NET Core OIDC middleware. +- Route protection via the auth/authorization middleware; profile page renders OIDC claims. +- Cookie-based session management with configurable idle timeout. +- Federated logout that clears the local session and redirects through Zitadel’s RP-initiated logout. + +--- + +## Getting started + +### Prerequisites + +- .NET SDK 8 or later + +### Account setup + +Create a Web application in Zitadel configured for Authorization Code + PKCE, then set: + +> **Redirect URIs:** `http://localhost:3000/auth/callback` +> **Post Logout Redirect URIs:** `http://localhost:3000/auth/logout/callback` + +These values must match the sample configuration. + +### Run the example + +1. Clone the repository: + ```bash + git clone https://github.com/zitadel/example-auth-dotnet.git + cd example-auth-dotnet + ``` +2. Copy `.env.example` to `.env` and fill in your values: + ```dotenv + PORT=3000 + SESSION_DURATION=3600 + ZITADEL_DOMAIN="https://your-zitadel-domain" + ZITADEL_CLIENT_ID="your-zitadel-application-client-id" + ZITADEL_CLIENT_SECRET="your-randomly-generated-client-secret" + ZITADEL_POST_LOGOUT_URL="http://localhost:3000/auth/logout/callback" + ``` +3. Start the dev server (restores dependencies automatically): + ```bash + make start + ``` + +The app will be available at `http://localhost:3000`. + +--- + +## Learn more and resources + +* [PKCE concept](https://oauth.net/2/pkce/) +* [ASP.NET Core OIDC handler](https://learn.microsoft.com/aspnet/core/security/authentication/openid-connect) +* [Zitadel OIDC guide](https://zitadel.com/docs/guides/integrate/login/oidc/login-users) +* [Federated logout](https://zitadel.com/docs/guides/integrate/login/oidc/logout) +* [Example repository](https://github.com/zitadel/example-auth-dotnet) diff --git a/apps/docs/frameworks.json b/apps/docs/frameworks.json index 49ad2e1df..728350e0f 100644 --- a/apps/docs/frameworks.json +++ b/apps/docs/frameworks.json @@ -19,6 +19,12 @@ "imgSrcDark": "/docs/img/tech/django.svg", "docsLink": "/docs/guides/start/quickstart?framework=django" }, + { + "id": "dotnet", + "title": ".NET", + "imgSrcDark": "/docs/img/tech/dotnet.svg", + "docsLink": "/docs/sdk-examples/dotnet" + }, { "id": "expressjs", "title": "Express.js", diff --git a/apps/docs/lib/sidebar-data.ts b/apps/docs/lib/sidebar-data.ts index 8d310a060..0d4f2cbde 100644 --- a/apps/docs/lib/sidebar-data.ts +++ b/apps/docs/lib/sidebar-data.ts @@ -384,6 +384,11 @@ export const guidesSidebar: readonly SidebarItem[] = [ "sdk-examples/client-libraries/php", ], }, + { + type: "category", + label: ".NET", + items: ["sdk-examples/dotnet"], + }, { type: "category", label: "Other Languages", diff --git a/console/src/app/utils/framework.ts b/console/src/app/utils/framework.ts index 638e24da4..25b61760b 100644 --- a/console/src/app/utils/framework.ts +++ b/console/src/app/utils/framework.ts @@ -106,6 +106,13 @@ export const OIDC_CONFIGURATIONS: OidcAppConfigurations = { .setGrantTypesList([OIDCGrantType.OIDC_GRANT_TYPE_AUTHORIZATION_CODE]) .setRedirectUrisList(['http://localhost:3000/auth/callback']) .setPostLogoutRedirectUrisList(['http://localhost:3000/auth/logout/callback']), + ['dotnet']: new AddOIDCAppRequest() + .setAppType(OIDCAppType.OIDC_APP_TYPE_WEB) + .setAuthMethodType(OIDCAuthMethodType.OIDC_AUTH_METHOD_TYPE_BASIC) + .setResponseTypesList([OIDCResponseType.OIDC_RESPONSE_TYPE_CODE]) + .setGrantTypesList([OIDCGrantType.OIDC_GRANT_TYPE_AUTHORIZATION_CODE]) + .setRedirectUrisList(['http://localhost:3000/auth/callback']) + .setPostLogoutRedirectUrisList(['http://localhost:3000/auth/logout/callback']), ['astro']: new AddOIDCAppRequest() .setAppType(OIDCAppType.OIDC_APP_TYPE_WEB) .setAuthMethodType(OIDCAuthMethodType.OIDC_AUTH_METHOD_TYPE_BASIC)