# Integrate Oidc

> Integrate ThunderID using a generic OIDC library for frameworks without an official ThunderID SDK — Angular, SvelteKit, Python, Go, .NET, and others. Use when asked to "add ThunderID to Angular", "integrate ThunderID with SvelteKit", or when no official SDK covers the target framework or language.

- **Type:** Skill
- **Install:** `agentstack add skill-thunder-id-skills-integrate-oidc`
- **Verified:** Yes — security-reviewed for prompt injection and unsafe behavior
- **Seller:** [thunder-id](https://agentstack.voostack.com/s/thunder-id)
- **Installs:** 0
- **Category:** [Agent Skills](https://agentstack.voostack.com/c/agent-skills)
- **Latest version:** 0.1.0
- **License:** Apache-2.0
- **Upstream author:** [thunder-id](https://github.com/thunder-id)
- **Source:** https://github.com/thunder-id/skills/tree/main/skills/integration/integrate-oidc

## Install

```sh
agentstack add skill-thunder-id-skills-integrate-oidc
```

Requires the [AgentStack CLI](https://agentstack.voostack.com/docs/cli). Works with Claude Code, Cursor, and any MCP-compatible agent.

## About

# ThunderID — Generic OIDC Integration

Assumes ThunderID is running at `https://localhost:8090`. If not, run `/setup-thunderid` first.

ThunderID is a standard OpenID Connect provider. Its discovery document is at:

```
https://localhost:8090/.well-known/openid-configuration
```

OIDC endpoints:

| Endpoint | URL |
|----------|-----|
| Discovery | `https://localhost:8090/.well-known/openid-configuration` |
| Authorization | `https://localhost:8090/oauth2/authorize` |
| Token | `https://localhost:8090/oauth2/token` |
| Userinfo | `https://localhost:8090/oauth2/userinfo` |
| JWKS | `https://localhost:8090/oauth2/jwks` |
| End session | `https://localhost:8090/oidc/logout` |

## Step 1 — Register an Application

Ask the developer to create an application in ThunderID and share the **Client ID** (and **Client Secret** for server-side apps) before continuing.

Guide them through these steps:

1. Open `https://localhost:8090/console` and sign in (default: `admin` / `secret`)
2. Navigate to **Applications → New Application**
3. Fill in:
   - **Name**: their app name
   - **Type**: Single Page Application for browser apps; Web Application for server-side
   - **Authorized Redirect URL**: their app's callback URL
4. Click **Create** and copy the **Client ID** (and **Client Secret** for server-side apps)

Once they paste the values, use them in all subsequent steps. Do **not** use placeholders — wait for the real values.

---

## Angular — `oidc-client-ts`

```bash
npm install oidc-client-ts
```

Create `src/auth.ts`:

```ts
import { UserManager, WebStorageStateStore } from 'oidc-client-ts'

export const userManager = new UserManager({
  authority: 'https://localhost:8090',
  client_id: '',
  redirect_uri: `${window.location.origin}/callback`,
  post_logout_redirect_uri: `${window.location.origin}`,
  response_type: 'code',
  scope: 'openid profile email',
  userStore: new WebStorageStateStore({ store: window.localStorage }),
})

export const signIn = () => userManager.signinRedirect()
export const signOut = () => userManager.signoutRedirect()
export const getUser = () => userManager.getUser()
```

Callback handler at the `/callback` route:

```ts
import { userManager } from './auth'
await userManager.signinRedirectCallback()
window.location.replace('/')
```

Route guard:

```ts
import { inject } from '@angular/core'
import { CanActivateFn, Router } from '@angular/router'
import { getUser } from './auth'

export const authGuard: CanActivateFn = async () => {
  const user = await getUser()
  if (!user || user.expired) {
    inject(Router).navigate(['/'])
    return false
  }
  return true
}
```

---

## SvelteKit — Auth.js

```bash
npm install @auth/sveltekit
```

`src/auth.ts`:

```ts
import { SvelteKitAuth } from '@auth/sveltekit'

export const { handle, signIn, signOut } = SvelteKitAuth({
  providers: [
    {
      id: 'thunderid',
      name: 'ThunderID',
      type: 'oidc',
      issuer: 'https://localhost:8090',
      clientId: '',
      clientSecret: '',
    },
  ],
})
```

`src/hooks.server.ts`:

```ts
export { handle } from './auth'
```

Protect a route in `+page.server.ts`:

```ts
import { redirect } from '@sveltejs/kit'
import type { PageServerLoad } from './$types'

export const load: PageServerLoad = async (event) => {
  const session = await event.locals.auth()
  if (!session) throw redirect(303, '/')
  return { session }
}
```

Sign-in / sign-out in a Svelte component:

```svelte

  import { signIn, signOut } from '@auth/sveltekit/client'
  import { page } from '$app/stores'

{#if $page.data.session}
   signOut()}>Sign Out
  Signed in as {$page.data.session.user?.email}
{:else}
   signIn('thunderid')}>Sign In
{/if}
```

---

## Python — `authlib`

```bash
pip install authlib httpx
```

```python
from authlib.integrations.httpx_client import AsyncOAuth2Client

client = AsyncOAuth2Client(
    client_id='',
    client_secret='',
    redirect_uri='http://localhost:8000/callback',
)

# Discover endpoints
metadata = await client.load_server_metadata('https://localhost:8090/.well-known/openid-configuration')

# Start login
uri, state = client.create_authorization_url(metadata['authorization_endpoint'], scope='openid profile email')

# In the callback handler
token = await client.fetch_token(metadata['token_endpoint'], authorization_response=str(request.url))
userinfo = await client.get(metadata['userinfo_endpoint'])
```

---

## Go — `coreos/go-oidc`

```bash
go get github.com/coreos/go-oidc/v3/oidc golang.org/x/oauth2
```

```go
provider, err := oidc.NewProvider(ctx, "https://localhost:8090")

config := oauth2.Config{
    ClientID:     "",
    ClientSecret: "",
    RedirectURL:  "http://localhost:8080/callback",
    Endpoint:     provider.Endpoint(),
    Scopes:       []string{oidc.ScopeOpenID, "profile", "email"},
}

// Start login
http.Redirect(w, r, config.AuthCodeURL(state), http.StatusFound)

// In /callback
token, err := config.Exchange(ctx, r.URL.Query().Get("code"))
idToken, err := provider.Verifier(&oidc.Config{ClientID: ""}).Verify(ctx, token.Extra("id_token").(string))

var claims struct {
    Email string `json:"email"`
    Name  string `json:"name"`
}
idToken.Claims(&claims)
```

---

## Troubleshooting

**Certificate error** — For browsers: visit `https://localhost:8090` and accept the warning. For Node.js: add `NODE_TLS_REJECT_UNAUTHORIZED=0` to `.env.local` (dev only). For Python: pass `verify=False` to the HTTP client (dev only). For Go: configure a custom TLS client.

**CORS error** — Ensure the redirect URI registered in the ThunderID console exactly matches the one used in code, including trailing slashes.

**`invalid_client`** — Double-check the Client ID and Client Secret.

## Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

- **Author:** [thunder-id](https://github.com/thunder-id)
- **Source:** [thunder-id/skills](https://github.com/thunder-id/skills)
- **License:** Apache-2.0

Install and usage instructions live in the source repository linked above.

## Pricing

- **Free** — Free

## Security capabilities

Automated source analysis of v0.1.0 — what this tool can access:

- **Network access:** yes
- **Filesystem access:** no
- **Shell / process execution:** no
- **Environment & secrets:** yes
- **Dynamic code execution:** no

*"Yes" means the capability is present in the source — more access means more to trust, not that it is unsafe.*


## Versions

- **0.1.0** — security scan: passed — Imported from the upstream source.

## Links

- Listing page: https://agentstack.voostack.com/l/skill-thunder-id-skills-integrate-oidc
- Seller: https://agentstack.voostack.com/s/thunder-id
- Browse the marketplace: https://agentstack.voostack.com/browse

---
Listed on AgentStack — the marketplace for AI agent skills and MCP servers. Every listing is security-reviewed. Creators keep 70%.
