Back to skills
SkillHub ClubShip Full StackFull Stack

oidc-hosted-page

Implement OIDC authentication using the MojoAuth Hosted Login Page — covers client configuration, user redirect, and callback token validation.

Packaged view

This page reorganizes the original catalog entry around fit, installability, and workflow context first. The original raw source lives below.

Stars
0
Hot score
74
Updated
March 20, 2026
Overall rating
C0.0
Composite score
0.0
Best-practice grade
C65.6

Install command

npx @skill-hub/cli install mojoauth-skills-oidc-hosted-page

Repository

MojoAuth/skills

Skill path: skills/authentication/oidc-hosted-page

Implement OIDC authentication using the MojoAuth Hosted Login Page — covers client configuration, user redirect, and callback token validation.

Open repository

Best for

Primary workflow: Ship Full Stack.

Technical facets: Full Stack.

Target audience: everyone.

License: Unknown.

Original source

Catalog source: SkillHub Club.

Repository owner: MojoAuth.

This is still a mirrored public skill entry. Review the repository before installing into production workflows.

What it helps with

  • Install oidc-hosted-page into Claude Code, Codex CLI, Gemini CLI, or OpenCode workflows
  • Review https://github.com/MojoAuth/skills before adding oidc-hosted-page to shared team environments
  • Use oidc-hosted-page for development workflows

Works across

Claude CodeCodex CLIGemini CLIOpenCode

Favorites: 0.

Sub-skills: 0.

Aggregator: No.

Original source / Raw SKILL.md

---
name: oidc-hosted-page
description: Implement OIDC authentication using the MojoAuth Hosted Login Page — covers client configuration, user redirect, and callback token validation.
---

# Implement MojoAuth OIDC Hosted Page

This skill guides you through implementing the OIDC Authorization Code flow with MojoAuth's Hosted Login Page. MojoAuth provides passwordless authentication (Magic Links, Email OTP, SMS OTP, Social Login, Passkeys) through a single hosted page — no need to build a login UI from scratch.

## 1. Prerequisites
- **Client ID**: From the MojoAuth Dashboard.
- **Client Secret**: From the MojoAuth Dashboard (store securely!).
- **Redirect URI**: Must be whitelisted in the MojoAuth Dashboard (e.g., `http://localhost:3000/callback`).
- **MojoAuth Domain**: Your application's MojoAuth domain (e.g., `https://your-app.mojoauth.com`).

## 2. Key OIDC Endpoints

All endpoints are relative to your MojoAuth domain (`https://your-app.mojoauth.com`):

| Endpoint | URL |
| :--- | :--- |
| **Discovery** | `/.well-known/openid-configuration` |
| **Authorization** | `/oauth/authorize` |
| **Token** | `/oauth2/token` |
| **UserInfo** | `/oauth/userinfo` |
| **JWKS** | `/.well-known/jwks.json` |

## 3. Implementation Steps

### Step 1: Configure OIDC Client
Initialize your OIDC client with the credentials above. Use a well-maintained OIDC library for your language. The discovery endpoint will auto-configure all URLs.

### Step 2: Redirect to MojoAuth Hosted Login Page
Construct the authorization URL and redirect the user. MojoAuth's Hosted Login Page handles all authentication methods (passwordless email, OTP, social login, passkeys).
- **Endpoint**: `/oauth/authorize`
- **Params**:
  - `response_type=code`
  - `client_id=YOUR_CLIENT_ID`
  - `redirect_uri=YOUR_REDIRECT_URI`
  - `scope=openid profile email`

### Step 3: Handle Callback
On the callback route (e.g., `/callback`):
1.  Extract the `code` parameter from the query string.
2.  Exchange the code for tokens at `/oauth2/token`.
3.  Verify the `id_token` signature using the JWKS endpoint (`/.well-known/jwks.json`).

## 4. Authentication Flow

```
User clicks "Sign In"
        │
        ▼
Redirect to MojoAuth Hosted Login Page
(https://your-app.mojoauth.com/oauth/authorize)
        │
        ▼
User authenticates via passwordless method
(Magic Link, OTP, Social Login, Passkeys)
        │
        ▼
MojoAuth redirects back with authorization code
        │
        ▼
Your server exchanges code for tokens
(POST /oauth2/token)
        │
        ▼
Verify ID token & create session
```

## 5. Examples
Refer to the platform-specific skill files for complete implementations:
- **Next.js**: [oidc-hosted-page-nextjs](../oidc-hosted-page-nextjs/SKILL.md)
- **Node.js**: [oidc-hosted-page-node](../oidc-hosted-page-node/SKILL.md)
- **Python**: [oidc-hosted-page-python](../oidc-hosted-page-python/SKILL.md)
- **Go**: [oidc-hosted-page-go](../oidc-hosted-page-go/SKILL.md)
- **React**: [oidc-hosted-page-react](../oidc-hosted-page-react/SKILL.md)
- **Angular**: [oidc-hosted-page-angular](../oidc-hosted-page-angular/SKILL.md)


---

## Referenced Files

> The following files are referenced in this skill and included for context.

### ../oidc-hosted-page-nextjs/SKILL.md

```markdown
---
name: oidc-hosted-page-nextjs
description: Implement passwordless authentication in Next.js applications using MojoAuth OIDC Hosted Login Page with the App Router.
---

# Implement MojoAuth OIDC (Next.js)

This expert AI assistant guide walks you through integrating passwordless authentication into a Next.js application using MojoAuth's Hosted Login Page as an OIDC identity provider. MojoAuth handles all authentication methods (Magic Links, Email OTP, SMS OTP, Social Login, Passkeys) through its hosted page — your app simply redirects there and handles the callback.

## 1. Prerequisites

- An existing Next.js application (App Router).
- Basic knowledge of Next.js and its common tools.
- An active MojoAuth account.
- [MojoAuth OIDC Setup Guide](https://docs.mojoauth.com/hosted-login-page/)
- Required library: `openid-client` (standard for Node.js OIDC integration).

## 2. Implementation Steps

### Step 1: Configure Application in MojoAuth

1. Log in to the [MojoAuth Dashboard](https://mojoauth.com/dashboard).
2. Note your **MojoAuth Domain** (e.g., `your-app.mojoauth.com`).
3. Configure the **Redirect URI** (e.g., `http://localhost:3000/api/auth/callback`).
4. Retrieve **Client ID** and **Client Secret**.
5. Enable your preferred authentication methods (Magic Link, Email OTP, Social Login, Passkeys).

### Step 2: Modify the Existing Next.js Project

#### Substep 2.1: Install Dependencies

Run the following command to install the required OIDC library:

```bash
npm install openid-client
```

#### Substep 2.2: Configure Environment Variables

Add to your `.env.local`:

```env
MOJOAUTH_DOMAIN=your-app.mojoauth.com
MOJOAUTH_CLIENT_ID=your_client_id
MOJOAUTH_CLIENT_SECRET=your_client_secret
MOJOAUTH_REDIRECT_URI=http://localhost:3000/api/auth/callback
```

#### Substep 2.3: Configure OIDC

Create a dedicated utility file for OIDC configuration (`lib/oidc.ts`):

```typescript
// lib/oidc.ts
import { Issuer } from 'openid-client';

let _client: any = null;

export async function getClient() {
  if (_client) return _client;

  const mojoauthIssuer = await Issuer.discover(
    `https://${process.env.MOJOAUTH_DOMAIN}`
  );

  _client = new mojoauthIssuer.Client({
    client_id: process.env.MOJOAUTH_CLIENT_ID!,
    client_secret: process.env.MOJOAUTH_CLIENT_SECRET!,
    redirect_uris: [process.env.MOJOAUTH_REDIRECT_URI!],
    response_types: ['code'],
  });

  return _client;
}
```

#### Substep 2.4: Update Login Page/UI

Create or modify your login page (`app/login/page.tsx`). Since MojoAuth handles all authentication on its Hosted Login Page, you only need a **"Sign In" button** that redirects the user:

```tsx
'use client';

import { useRouter } from 'next/navigation';

export default function LoginPage() {
  const router = useRouter();

  const handleLogin = () => {
    // Redirect to the API route that initiates MojoAuth OIDC flow
    window.location.href = '/api/auth/login';
  };

  return (
    <div className="login-container">
      <h1>Welcome</h1>
      <p>Sign in with your preferred method — passwordless, social login, or passkeys.</p>

      <button
        onClick={handleLogin}
        className="bg-blue-600 text-white p-3 rounded-lg w-full"
      >
        Sign In with MojoAuth
      </button>

      <p className="text-sm text-gray-500 mt-4">
        Powered by MojoAuth — Passwordless Authentication
      </p>
    </div>
  );
}
```

#### Substep 2.5: Update Backend Logic

Create the necessary API routes to handle the OIDC flow.

**1. Login Initiation Route** (`app/api/auth/login/route.ts`):

```typescript
import { NextResponse } from 'next/server';
import { getClient } from '@/lib/oidc';

export async function GET(request: Request) {
  const client = await getClient();

  // Generate a random state for CSRF protection
  const state = Math.random().toString(36).substring(2, 15);

  const authorizationUrl = client.authorizationUrl({
    scope: 'openid profile email',
    state,
  });

  const response = NextResponse.redirect(authorizationUrl);
  // Store state in a cookie to verify in the callback
  response.cookies.set('oidc_state', state, {
    httpOnly: true,
    secure: true,
    sameSite: 'lax',
    maxAge: 3600,
  });

  return response;
}
```

**2. Callback Handler Route** (`app/api/auth/callback/route.ts`):

```typescript
import { NextRequest, NextResponse } from 'next/server';
import { getClient } from '@/lib/oidc';

export async function GET(request: NextRequest) {
  const client = await getClient();
  const params = client.callbackParams(request.url);

  try {
    const storedState = request.cookies.get('oidc_state')?.value;
    const tokenSet = await client.callback(
      process.env.MOJOAUTH_REDIRECT_URI,
      params,
      { state: storedState }
    );
    const userinfo = await client.userinfo(tokenSet.access_token!);

    // TODO: Create a session for the user based on `userinfo`
    // userinfo contains: sub, name, email, email_verified, etc.
    console.log('Authenticated User:', userinfo);

    // Redirect to the dashboard or intended page
    return NextResponse.redirect(new URL('/dashboard', request.url));
  } catch (error) {
    console.error('OIDC Callback Error:', error);
    return NextResponse.redirect(new URL('/login?error=auth_failed', request.url));
  }
}
```

### Step 3: Test the Implementation

1. Start your application: `npm run dev`.
2. Navigate to your login page (e.g., `/login`).
3. Click **"Sign In with MojoAuth"**.
4. You should be redirected to the MojoAuth Hosted Login Page.
5. Authenticate using any available method (Magic Link, OTP, Social Login, Passkeys).
6. After successful authentication, you should be redirected back to `/api/auth/callback` and then to `/dashboard`.

## 3. Additional Considerations

- **Error Handling**: Enhance the callback route to handle specific OIDC errors gracefully.
- **Styling**: Adapt the login page to match your application's design system.
- **Security**: Integrate the user information returned in the callback with your existing session management system (e.g., setting cookies or JWTs).
- **Environment Variables**: Store sensitive values like `MOJOAUTH_CLIENT_SECRET` in `.env.local` and access them via `process.env`.
- **MojoAuth Hosted Page Customization**: Customize the look and feel of the Hosted Login Page from the MojoAuth Dashboard to match your brand.

## 4. Support

- **MojoAuth Documentation**: [mojoauth.com/docs](https://mojoauth.com/docs)
- **Check application logs**: Use server-side logging to debug OIDC flow issues.
- **Library Documentation**: Refer to the [openid-client documentation](https://github.com/panva/node-openid-client) for advanced configuration.

```

### ../oidc-hosted-page-node/SKILL.md

```markdown
---
name: oidc-hosted-page-node
description: Implement passwordless authentication in Node.js Express applications using MojoAuth OIDC Hosted Login Page.
---

# Implement MojoAuth OIDC (Node.js / Express)

This expert AI assistant guide walks you through integrating passwordless authentication into an existing Node.js Express application using MojoAuth's Hosted Login Page as an OIDC identity provider. MojoAuth handles all authentication methods (Magic Links, Email OTP, SMS OTP, Social Login, Passkeys) through its hosted page.

## 1. Prerequisites

- An existing Node.js application with Express.
- Basic knowledge of Express.js routing and middleware.
- An active MojoAuth account.
- [MojoAuth OIDC Setup Guide](https://docs.mojoauth.com/hosted-login-page/)
- Required libraries: `openid-client`, `express-session`.

## 2. Implementation Steps

### Step 1: Configure Application in MojoAuth

1. Log in to the [MojoAuth Dashboard](https://mojoauth.com/dashboard).
2. Note your **MojoAuth Domain** (e.g., `your-app.mojoauth.com`).
3. Configure the **Redirect URI** (e.g., `http://localhost:3000/auth/callback`).
4. Retrieve **Client ID** and **Client Secret**.
5. Enable your preferred authentication methods.

### Step 2: Modify the Existing Node.js Project

#### Substep 2.1: Install Dependencies

Run the following command to install the required libraries:

```bash
npm install openid-client express-session dotenv
```

#### Substep 2.2: Configure Environment Variables

Create a `.env` file in the project root:

```env
MOJOAUTH_DOMAIN=your-app.mojoauth.com
MOJOAUTH_CLIENT_ID=your_client_id
MOJOAUTH_CLIENT_SECRET=your_client_secret
MOJOAUTH_REDIRECT_URI=http://localhost:3000/auth/callback
SESSION_SECRET=a_strong_random_secret
PORT=3000
```

#### Substep 2.3: Configure OIDC Client

Create a dedicated utility file for OIDC configuration (e.g., `lib/oidc.js`):

```javascript
// lib/oidc.js
const { Issuer } = require('openid-client');

let _client = null;

async function getClient() {
  if (_client) return _client;

  const mojoauthIssuer = await Issuer.discover(
    `https://${process.env.MOJOAUTH_DOMAIN}`
  );

  _client = new mojoauthIssuer.Client({
    client_id: process.env.MOJOAUTH_CLIENT_ID,
    client_secret: process.env.MOJOAUTH_CLIENT_SECRET,
    redirect_uris: [process.env.MOJOAUTH_REDIRECT_URI],
    response_types: ['code'],
  });

  return _client;
}

module.exports = { getClient };
```

#### Substep 2.4: Update Login Page/UI

Since MojoAuth handles all authentication on its Hosted Login Page, your login page only needs a **"Sign In" button**:

```html
<!-- views/login.ejs -->
<div class="login-container">
  <h1>Welcome</h1>
  <p>Sign in with your preferred method — passwordless, social login, or passkeys.</p>

  <a href="/auth/login" class="sign-in-button">Sign In with MojoAuth</a>

  <p class="powered-by">Powered by MojoAuth — Passwordless Authentication</p>
</div>
```

#### Substep 2.5: Update Backend Logic

Create the necessary routes to handle the OIDC flow.

**1. Login Route** (`routes/auth.js`):

```javascript
// routes/auth.js
const express = require('express');
const router = express.Router();
const { getClient } = require('../lib/oidc');

// Initiate MojoAuth OIDC login
router.get('/login', async (req, res) => {
  const client = await getClient();

  // Generate a random state for CSRF protection
  const state = Math.random().toString(36).substring(2, 15);
  req.session.oidc_state = state;

  const authorizationUrl = client.authorizationUrl({
    scope: 'openid profile email',
    state,
  });

  return res.redirect(authorizationUrl);
});

module.exports = router;
```

**2. Callback Handler Route** (`routes/callback.js`):

```javascript
// routes/callback.js
const express = require('express');
const router = express.Router();
const { getClient } = require('../lib/oidc');

router.get('/callback', async (req, res) => {
  const client = await getClient();
  const params = client.callbackParams(req);

  try {
    const storedState = req.session.oidc_state;
    const tokenSet = await client.callback(
      process.env.MOJOAUTH_REDIRECT_URI,
      params,
      { state: storedState }
    );
    const userinfo = await client.userinfo(tokenSet.access_token);

    // Clear the OIDC state from session
    delete req.session.oidc_state;

    // TODO: Create a session for the user based on `userinfo`
    req.session.user = userinfo;
    console.log('Authenticated User:', userinfo);

    // Redirect to the dashboard or intended page
    res.redirect('/dashboard');
  } catch (error) {
    console.error('OIDC Callback Error:', error);
    res.redirect('/login?error=auth_failed');
  }
});

module.exports = router;
```

**3. Main Application Setup** (`app.js`):

```javascript
// app.js
require('dotenv').config();
const express = require('express');
const session = require('express-session');

const authRoutes = require('./routes/auth');
const callbackRoutes = require('./routes/callback');

const app = express();

app.set('view engine', 'ejs');
app.use(express.urlencoded({ extended: true }));
app.use(session({
  secret: process.env.SESSION_SECRET,
  resave: false,
  saveUninitialized: false,
  cookie: { secure: false, httpOnly: true, maxAge: 3600000 },
}));

// Routes
app.get('/login', (req, res) => res.render('login'));
app.use('/auth', authRoutes);
app.use('/auth', callbackRoutes);

app.get('/dashboard', (req, res) => {
  if (!req.session.user) return res.redirect('/login');
  res.send(`<h1>Dashboard</h1><pre>${JSON.stringify(req.session.user, null, 2)}</pre><a href="/auth/logout">Logout</a>`);
});

app.get('/auth/logout', (req, res) => {
  req.session.destroy();
  res.redirect('/login');
});

app.listen(process.env.PORT || 3000, () => {
  console.log(`Server running on http://localhost:${process.env.PORT || 3000}`);
});
```

### Step 3: Test the Implementation

1. Start your application: `node app.js`.
2. Navigate to `http://localhost:3000/login`.
3. Click **"Sign In with MojoAuth"**.
4. You should be redirected to the MojoAuth Hosted Login Page.
5. Authenticate using any available method.
6. After successful authentication, you should be redirected back to `/auth/callback` and then to `/dashboard`.

## 3. Additional Considerations

- **Error Handling**: Enhance the callback route to handle specific OIDC errors gracefully.
- **Styling**: Adapt the example HTML/CSS to match your application's design system.
- **Security**: Use `express-session` with a production-ready store (e.g., Redis, MongoDB) and enable `secure: true` for cookies in production.
- **Environment Variables**: Never commit `.env` to source control. Use secrets management in production.

## 4. Support

- **MojoAuth Documentation**: [mojoauth.com/docs](https://mojoauth.com/docs)
- **Check application logs**: Use server-side logging to debug OIDC flow issues.
- **Library Documentation**: Refer to the [openid-client documentation](https://github.com/panva/node-openid-client) for advanced configuration.

```

### ../oidc-hosted-page-python/SKILL.md

```markdown
---
name: oidc-hosted-page-python
description: Implement passwordless authentication in Python Flask applications using MojoAuth OIDC Hosted Login Page.
---

# Implement MojoAuth OIDC (Python / Flask)

This expert AI assistant guide walks you through integrating passwordless authentication into a Python Flask application using MojoAuth's Hosted Login Page as an OIDC identity provider. MojoAuth handles all authentication methods (Magic Links, Email OTP, SMS OTP, Social Login, Passkeys) through its hosted page.

## 1. Prerequisites

- An existing Python Flask application.
- Python 3.8+ installed.
- An active MojoAuth account.
- [MojoAuth OIDC Setup Guide](https://docs.mojoauth.com/hosted-login-page/)
- Required libraries: `authlib`, `flask`, `python-dotenv`.

## 2. Implementation Steps

### Step 1: Configure Application in MojoAuth

1. Log in to the [MojoAuth Dashboard](https://mojoauth.com/dashboard).
2. Note your **MojoAuth Domain** (e.g., `your-app.mojoauth.com`).
3. Configure the **Redirect URI** (e.g., `http://localhost:5000/auth/callback`).
4. Retrieve **Client ID** and **Client Secret**.
5. Enable your preferred authentication methods.

### Step 2: Modify the Existing Flask Project

#### Substep 2.1: Install Dependencies

```bash
pip install authlib flask python-dotenv requests
```

#### Substep 2.2: Configure Environment Variables

Create a `.env` file in the project root:

```env
MOJOAUTH_DOMAIN=your-app.mojoauth.com
MOJOAUTH_CLIENT_ID=your_client_id
MOJOAUTH_CLIENT_SECRET=your_client_secret
MOJOAUTH_REDIRECT_URI=http://localhost:5000/auth/callback
FLASK_SECRET_KEY=a_strong_random_secret
```

#### Substep 2.3: Configure OIDC Client

Create a dedicated utility file for OIDC configuration (e.g., `lib/oidc.py`):

```python
# lib/oidc.py
import os
from authlib.integrations.flask_client import OAuth

oauth = OAuth()

def init_oauth(app):
    """Initialize the OAuth registry with the MojoAuth provider."""
    oauth.init_app(app)
    oauth.register(
        name='mojoauth',
        client_id=os.getenv('MOJOAUTH_CLIENT_ID'),
        client_secret=os.getenv('MOJOAUTH_CLIENT_SECRET'),
        server_metadata_url=f"https://{os.getenv('MOJOAUTH_DOMAIN')}/.well-known/openid-configuration",
        client_kwargs={
            'scope': 'openid profile email',
        },
    )
```

#### Substep 2.4: Update Login Page/UI

Since MojoAuth handles all authentication on its Hosted Login Page, your login page only needs a **"Sign In" link**:

```html
<!-- templates/login.html -->
<!DOCTYPE html>
<html>
<head><title>Sign In</title></head>
<body>
  <div class="login-container">
    <h1>Welcome</h1>
    <p>Sign in with your preferred method — passwordless, social login, or passkeys.</p>

    {% if error %}
      <p style="color: red;">{{ error }}</p>
    {% endif %}

    <a href="/auth/login" class="sign-in-button">Sign In with MojoAuth</a>

    <p class="powered-by">Powered by MojoAuth — Passwordless Authentication</p>
  </div>
</body>
</html>
```

#### Substep 2.5: Update Backend Logic

**Main Application Setup** (`app.py`):

```python
# app.py
import os
import secrets
from dotenv import load_dotenv
from flask import Flask, redirect, url_for, session, render_template, request
from lib.oidc import oauth, init_oauth

load_dotenv()

app = Flask(__name__)
app.secret_key = os.getenv('FLASK_SECRET_KEY')

# Initialize OAuth
init_oauth(app)


@app.route('/login')
def login_page():
    error = request.args.get('error')
    return render_template('login.html', error=error)


@app.route('/auth/login')
def login():
    # Generate a random state for CSRF protection
    state = secrets.token_urlsafe(16)
    session['oidc_state'] = state

    redirect_uri = os.getenv('MOJOAUTH_REDIRECT_URI')
    return oauth.mojoauth.authorize_redirect(
        redirect_uri,
        state=state,
    )


@app.route('/auth/callback')
def callback():
    try:
        # Verify state
        stored_state = session.pop('oidc_state', None)
        received_state = request.args.get('state')

        if stored_state != received_state:
            return redirect('/login?error=state_mismatch')

        token = oauth.mojoauth.authorize_access_token()
        userinfo = token.get('userinfo')

        if not userinfo:
            userinfo = oauth.mojoauth.userinfo()

        # TODO: Create a session for the user based on `userinfo`
        session['user'] = dict(userinfo)
        print('Authenticated User:', userinfo)

        # Redirect to the dashboard or intended page
        return redirect('/dashboard')
    except Exception as e:
        print(f'OIDC Callback Error: {e}')
        return redirect('/login?error=auth_failed')


@app.route('/dashboard')
def dashboard():
    user = session.get('user')
    if not user:
        return redirect('/login')
    return f"<h1>Dashboard</h1><pre>{user}</pre><a href='/auth/logout'>Logout</a>"


@app.route('/auth/logout')
def logout():
    session.clear()
    return redirect('/login')


if __name__ == '__main__':
    app.run(debug=True, port=5000)
```

### Step 3: Test the Implementation

1. Start your application: `python app.py`.
2. Navigate to `http://localhost:5000/login`.
3. Click **"Sign In with MojoAuth"**.
4. You should be redirected to the MojoAuth Hosted Login Page.
5. Authenticate using any available method.
6. After successful authentication, you should be redirected back to `/auth/callback` and then to `/dashboard`.

## 3. Additional Considerations

- **Error Handling**: Enhance the callback route to handle specific OIDC errors gracefully.
- **Styling**: Adapt the example HTML/CSS to match your application's design system.
- **Security**: Use a production-grade session backend (e.g., Redis via `flask-session`) and serve over HTTPS.
- **Environment Variables**: Never commit `.env` to source control. Use secrets management in production.

## 4. Support

- **MojoAuth Documentation**: [mojoauth.com/docs](https://mojoauth.com/docs)
- **Check application logs**: Use server-side logging to debug OIDC flow issues.
- **Library Documentation**: Refer to the [Authlib documentation](https://docs.authlib.org/en/latest/) for advanced configuration.

```

### ../oidc-hosted-page-go/SKILL.md

```markdown
---
name: oidc-hosted-page-go
description: Implement passwordless authentication in Go applications using MojoAuth OIDC Hosted Login Page.
---

# Implement MojoAuth OIDC (Go)

This expert AI assistant guide walks you through integrating passwordless authentication into a Go application using MojoAuth's Hosted Login Page as an OIDC identity provider. MojoAuth handles all authentication methods (Magic Links, Email OTP, SMS OTP, Social Login, Passkeys) through its hosted page.

## 1. Prerequisites

- An existing Go application (1.21+).
- Basic knowledge of Go's `net/http` or a web framework like `chi` or `gorilla/mux`.
- An active MojoAuth account.
- [MojoAuth OIDC Setup Guide](https://docs.mojoauth.com/hosted-login-page/)
- Required packages: `github.com/coreos/go-oidc/v3/oidc`, `golang.org/x/oauth2`.

## 2. Implementation Steps

### Step 1: Configure Application in MojoAuth

1. Log in to the [MojoAuth Dashboard](https://mojoauth.com/dashboard).
2. Note your **MojoAuth Domain** (e.g., `your-app.mojoauth.com`).
3. Configure the **Redirect URI** (e.g., `http://localhost:8080/auth/callback`).
4. Retrieve **Client ID** and **Client Secret**.
5. Enable your preferred authentication methods.

### Step 2: Modify the Existing Go Project

#### Substep 2.1: Install Dependencies

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

#### Substep 2.2: Configure Environment Variables

Set the following environment variables (or use a `.env` loader like `godotenv`):

```env
MOJOAUTH_DOMAIN=your-app.mojoauth.com
MOJOAUTH_CLIENT_ID=your_client_id
MOJOAUTH_CLIENT_SECRET=your_client_secret
MOJOAUTH_REDIRECT_URI=http://localhost:8080/auth/callback
```

#### Substep 2.3: Configure OIDC Provider

Create a dedicated file for OIDC configuration (e.g., `internal/auth/oidc.go`):

```go
// internal/auth/oidc.go
package auth

import (
	"context"
	"fmt"
	"os"

	"github.com/coreos/go-oidc/v3/oidc"
	"golang.org/x/oauth2"
)

var (
	OIDCProvider *oidc.Provider
	OAuth2Config oauth2.Config
)

func InitOIDC() error {
	ctx := context.Background()

	issuerURL := fmt.Sprintf("https://%s", os.Getenv("MOJOAUTH_DOMAIN"))
	provider, err := oidc.NewProvider(ctx, issuerURL)
	if err != nil {
		return err
	}
	OIDCProvider = provider

	OAuth2Config = oauth2.Config{
		ClientID:     os.Getenv("MOJOAUTH_CLIENT_ID"),
		ClientSecret: os.Getenv("MOJOAUTH_CLIENT_SECRET"),
		RedirectURL:  os.Getenv("MOJOAUTH_REDIRECT_URI"),
		Endpoint:     provider.Endpoint(),
		Scopes:       []string{oidc.ScopeOpenID, "profile", "email"},
	}

	return nil
}
```

#### Substep 2.4: Update Login Page/UI

Since MojoAuth handles all authentication on its Hosted Login Page, your login page only needs a **"Sign In" link**:

```html
<!-- templates/login.html -->
<!DOCTYPE html>
<html>
<head><title>Sign In</title></head>
<body>
  <div class="login-container">
    <h1>Welcome</h1>
    <p>Sign in with your preferred method — passwordless, social login, or passkeys.</p>

    {{if .Error}}
      <p style="color: red;">{{.Error}}</p>
    {{end}}

    <a href="/auth/login" class="sign-in-button">Sign In with MojoAuth</a>

    <p class="powered-by">Powered by MojoAuth — Passwordless Authentication</p>
  </div>
</body>
</html>
```

#### Substep 2.5: Update Backend Logic

Create the necessary handlers to process the OIDC flow.

**1. Login Handler** (`internal/auth/handlers.go`):

```go
// internal/auth/handlers.go
package auth

import (
	"crypto/rand"
	"encoding/base64"
	"encoding/json"
	"log"
	"net/http"

	"github.com/coreos/go-oidc/v3/oidc"
)

func generateState() string {
	b := make([]byte, 16)
	rand.Read(b)
	return base64.URLEncoding.EncodeToString(b)
}

// LoginHandler initiates the MojoAuth OIDC flow.
func LoginHandler(w http.ResponseWriter, r *http.Request) {
	// Generate a random state for CSRF protection
	state := generateState()

	// Store state in a cookie
	http.SetCookie(w, &http.Cookie{
		Name:     "oidc_state",
		Value:    state,
		Path:     "/",
		HttpOnly: true,
		Secure:   true,
		SameSite: http.SameSiteLaxMode,
		MaxAge:   3600,
	})

	// Build authorization URL — redirects to MojoAuth Hosted Login Page
	authURL := OAuth2Config.AuthCodeURL(state)

	http.Redirect(w, r, authURL, http.StatusFound)
}
```

**2. Callback Handler** (add to `internal/auth/handlers.go`):

```go
// CallbackHandler handles the OIDC callback.
func CallbackHandler(w http.ResponseWriter, r *http.Request) {
	// Retrieve stored state from cookie
	stateCookie, err := r.Cookie("oidc_state")
	if err != nil {
		log.Println("State cookie not found:", err)
		http.Redirect(w, r, "/login?error=state_missing", http.StatusFound)
		return
	}

	// Verify state
	if r.URL.Query().Get("state") != stateCookie.Value {
		log.Println("State mismatch")
		http.Redirect(w, r, "/login?error=state_mismatch", http.StatusFound)
		return
	}

	// Exchange authorization code for token
	code := r.URL.Query().Get("code")
	token, err := OAuth2Config.Exchange(r.Context(), code)
	if err != nil {
		log.Println("Token exchange failed:", err)
		http.Redirect(w, r, "/login?error=token_exchange_failed", http.StatusFound)
		return
	}

	// Extract and verify ID token
	rawIDToken, ok := token.Extra("id_token").(string)
	if !ok {
		log.Println("No id_token in response")
		http.Redirect(w, r, "/login?error=no_id_token", http.StatusFound)
		return
	}

	verifier := OIDCProvider.Verifier(&oidc.Config{ClientID: OAuth2Config.ClientID})
	idToken, err := verifier.Verify(r.Context(), rawIDToken)
	if err != nil {
		log.Println("ID token verification failed:", err)
		http.Redirect(w, r, "/login?error=token_verification_failed", http.StatusFound)
		return
	}

	// Extract user claims
	var claims map[string]interface{}
	if err := idToken.Claims(&claims); err != nil {
		log.Println("Failed to parse claims:", err)
		http.Redirect(w, r, "/login?error=claims_parse_failed", http.StatusFound)
		return
	}

	// Clear the state cookie
	http.SetCookie(w, &http.Cookie{
		Name:   "oidc_state",
		Value:  "",
		Path:   "/",
		MaxAge: -1,
	})

	// TODO: Create a session for the user based on claims
	claimsJSON, _ := json.Marshal(claims)
	http.SetCookie(w, &http.Cookie{
		Name:     "user_session",
		Value:    base64.URLEncoding.EncodeToString(claimsJSON),
		Path:     "/",
		HttpOnly: true,
		MaxAge:   3600,
	})

	log.Println("Authenticated User:", claims)

	// Redirect to the dashboard or intended page
	http.Redirect(w, r, "/dashboard", http.StatusFound)
}
```

**3. Main Application Setup** (`main.go`):

```go
// main.go
package main

import (
	"log"
	"net/http"
	"html/template"

	"yourmodule/internal/auth"
)

func main() {
	// Initialize OIDC
	if err := auth.InitOIDC(); err != nil {
		log.Fatal("Failed to initialize OIDC:", err)
	}

	// Routes
	http.HandleFunc("/login", func(w http.ResponseWriter, r *http.Request) {
		tmpl := template.Must(template.ParseFiles("templates/login.html"))
		data := map[string]string{"Error": r.URL.Query().Get("error")}
		tmpl.Execute(w, data)
	})

	http.HandleFunc("/auth/login", auth.LoginHandler)
	http.HandleFunc("/auth/callback", auth.CallbackHandler)
	http.HandleFunc("/dashboard", func(w http.ResponseWriter, r *http.Request) {
		w.Write([]byte("<h1>Dashboard</h1><p>Welcome!</p>"))
	})

	log.Println("Server running on http://localhost:8080")
	log.Fatal(http.ListenAndServe(":8080", nil))
}
```

### Step 3: Test the Implementation

1. Start your application: `go run main.go`.
2. Navigate to `http://localhost:8080/login`.
3. Click **"Sign In with MojoAuth"**.
4. You should be redirected to the MojoAuth Hosted Login Page.
5. Authenticate using any available method.
6. After successful authentication, you should be redirected back to `/auth/callback` and then to `/dashboard`.

## 3. Additional Considerations

- **Error Handling**: Enhance the callback handler with granular OIDC error parsing.
- **Styling**: Adapt the example HTML/CSS to match your application's design system.
- **Security**: Use a proper session library (e.g., `gorilla/sessions`) instead of raw cookies in production.
- **Environment Variables**: Use a library like `godotenv` for local development and proper secrets management in production.

## 4. Support

- **MojoAuth Documentation**: [mojoauth.com/docs](https://mojoauth.com/docs)
- **Check application logs**: Use server-side logging to debug OIDC flow issues.
- **Library Documentation**: Refer to the [go-oidc documentation](https://github.com/coreos/go-oidc) and [oauth2 documentation](https://pkg.go.dev/golang.org/x/oauth2) for advanced configuration.

```

### ../oidc-hosted-page-react/SKILL.md

```markdown
---
name: oidc-hosted-page-react
description: Implement passwordless authentication in React SPA applications using MojoAuth OIDC Hosted Login Page with PKCE.
---

# Implement MojoAuth OIDC (React)

This expert AI assistant guide walks you through integrating passwordless authentication into an existing React application using MojoAuth's Hosted Login Page as an OIDC identity provider. MojoAuth handles all authentication methods (Magic Links, Email OTP, SMS OTP, Social Login, Passkeys) through its hosted page — your app simply redirects there and handles the callback.

## 1. Prerequisites

- An existing React 18+ application (e.g., created with Vite or Create React App).
- Basic knowledge of React hooks and React Router.
- An active MojoAuth account.
- [MojoAuth OIDC Setup Guide](https://docs.mojoauth.com/hosted-login-page/)
- Required libraries: `oidc-client-ts`, `react-oidc-context`.

## 2. Implementation Steps

### Step 1: Configure Application in MojoAuth

1. Log in to the [MojoAuth Dashboard](https://mojoauth.com/dashboard).
2. Note your **MojoAuth Domain** (e.g., `your-app.mojoauth.com`).
3. Configure the **Redirect URI** (e.g., `http://localhost:5173/auth/callback`).
4. Retrieve **Client ID**.
5. Enable your preferred authentication methods (Magic Link, Email OTP, Social Login, Passkeys).

> **Note:** For SPAs, the recommended flow is **Authorization Code with PKCE** (no Client Secret required on the front-end).

### Step 2: Modify the Existing React Project

#### Substep 2.1: Install Dependencies

Run the following command to install the required libraries:

```bash
npm install oidc-client-ts react-oidc-context react-router-dom
```

#### Substep 2.2: Configure OIDC Provider

Create a dedicated configuration file (e.g., `src/lib/oidcConfig.ts`):

```typescript
// src/lib/oidcConfig.ts
import { WebStorageStateStore } from 'oidc-client-ts';

export const oidcConfig = {
  authority: 'https://your-app.mojoauth.com', // Your MojoAuth Domain
  client_id: 'your_client_id',
  redirect_uri: 'http://localhost:5173/auth/callback',
  post_logout_redirect_uri: 'http://localhost:5173/',
  response_type: 'code',
  scope: 'openid profile email',
  userStore: new WebStorageStateStore({ store: window.localStorage }),
};
```

#### Substep 2.3: Wrap App with Auth Provider

Update your `src/main.tsx` to wrap the application with the OIDC provider:

```tsx
// src/main.tsx
import React from 'react';
import ReactDOM from 'react-dom/client';
import { BrowserRouter } from 'react-router-dom';
import { AuthProvider } from 'react-oidc-context';
import { oidcConfig } from './lib/oidcConfig';
import App from './App';

ReactDOM.createRoot(document.getElementById('root')!).render(
  <React.StrictMode>
    <AuthProvider {...oidcConfig}>
      <BrowserRouter>
        <App />
      </BrowserRouter>
    </AuthProvider>
  </React.StrictMode>
);
```

#### Substep 2.4: Update Login Page/UI

Since MojoAuth handles all authentication on its Hosted Login Page, your login page only needs a **"Sign In" button** that triggers the OIDC redirect:

```tsx
// src/pages/Login.tsx
import { useAuth } from 'react-oidc-context';

export default function LoginPage() {
  const auth = useAuth();

  const handleLogin = () => {
    // Redirect to MojoAuth Hosted Login Page via OIDC
    auth.signinRedirect();
  };

  return (
    <div className="login-container">
      <h1>Welcome</h1>
      <p>Sign in with your preferred method — passwordless, social login, or passkeys.</p>

      <button onClick={handleLogin}>
        Sign In with MojoAuth
      </button>

      <p className="powered-by">
        Powered by MojoAuth — Passwordless Authentication
      </p>
    </div>
  );
}
```

#### Substep 2.5: Create Callback Component

Create a callback component to handle the OIDC redirect (e.g., `src/pages/AuthCallback.tsx`):

```tsx
// src/pages/AuthCallback.tsx
import { useEffect } from 'react';
import { useAuth } from 'react-oidc-context';
import { useNavigate } from 'react-router-dom';

export default function AuthCallback() {
  const auth = useAuth();
  const navigate = useNavigate();

  useEffect(() => {
    if (auth.isAuthenticated) {
      console.log('Authenticated User:', auth.user?.profile);
      navigate('/dashboard');
    }
    if (auth.error) {
      console.error('OIDC Callback Error:', auth.error);
      navigate('/?error=auth_failed');
    }
  }, [auth.isAuthenticated, auth.error, navigate]);

  if (auth.isLoading) {
    return <p>Authenticating...</p>;
  }

  return null;
}
```

#### Substep 2.6: Configure Routes

Update your `src/App.tsx` to include the callback route:

```tsx
// src/App.tsx
import { Routes, Route } from 'react-router-dom';
import LoginPage from './pages/Login';
import AuthCallback from './pages/AuthCallback';
import Dashboard from './pages/Dashboard';

export default function App() {
  return (
    <Routes>
      <Route path="/" element={<LoginPage />} />
      <Route path="/auth/callback" element={<AuthCallback />} />
      <Route path="/dashboard" element={<Dashboard />} />
    </Routes>
  );
}
```

**Dashboard Page** (`src/pages/Dashboard.tsx`):

```tsx
// src/pages/Dashboard.tsx
import { useAuth } from 'react-oidc-context';
import { Navigate } from 'react-router-dom';

export default function Dashboard() {
  const auth = useAuth();

  if (!auth.isAuthenticated) {
    return <Navigate to="/" />;
  }

  return (
    <div>
      <h1>Dashboard</h1>
      <pre>{JSON.stringify(auth.user?.profile, null, 2)}</pre>
      <button onClick={() => auth.signoutRedirect()}>Logout</button>
    </div>
  );
}
```

### Step 3: Test the Implementation

1. Start your application: `npm run dev`.
2. Navigate to `http://localhost:5173/`.
3. Click **"Sign In with MojoAuth"**.
4. You should be redirected to the MojoAuth Hosted Login Page.
5. Authenticate using any available method (Magic Link, OTP, Social Login, Passkeys).
6. After successful authentication, you should be redirected back to `/auth/callback` and then to `/dashboard`.

## 3. Additional Considerations

- **Error Handling**: Use `auth.error` from the `useAuth` hook to display authentication errors in the UI.
- **Styling**: Adapt the example JSX to match your application's design system (e.g., Material UI, Chakra UI).
- **Security**: Since this is a SPA, **PKCE** is automatically handled by `oidc-client-ts`. Never store a Client Secret in the front-end.
- **Protected Routes**: Create a wrapper component that checks `auth.isAuthenticated` before rendering child routes.
- **MojoAuth Hosted Page Customization**: Customize the look and feel of the Hosted Login Page from the MojoAuth Dashboard to match your brand.

## 4. Support

- **MojoAuth Documentation**: [mojoauth.com/docs](https://mojoauth.com/docs)
- **Check browser console**: Use browser developer tools to debug OIDC flow issues.
- **Library Documentation**: Refer to the [react-oidc-context documentation](https://github.com/authts/react-oidc-context) and [oidc-client-ts documentation](https://github.com/authts/oidc-client-ts) for advanced configuration.

```

### ../oidc-hosted-page-angular/SKILL.md

```markdown
---
name: oidc-hosted-page-angular
description: Implement passwordless authentication in Angular SPA applications using MojoAuth OIDC Hosted Login Page with PKCE.
---

# Implement MojoAuth OIDC (Angular)

This expert AI assistant guide walks you through integrating passwordless authentication into an Angular application using MojoAuth's Hosted Login Page as an OIDC identity provider. MojoAuth handles all authentication methods (Magic Links, Email OTP, SMS OTP, Social Login, Passkeys) through its hosted page.

## 1. Prerequisites

- An existing Angular 15+ application.
- Basic knowledge of Angular routing, services, and components.
- An active MojoAuth account.
- [MojoAuth OIDC Setup Guide](https://docs.mojoauth.com/hosted-login-page/)
- Required library: `angular-auth-oidc-client`.

## 2. Implementation Steps

### Step 1: Configure Application in MojoAuth

1. Log in to the [MojoAuth Dashboard](https://mojoauth.com/dashboard).
2. Note your **MojoAuth Domain** (e.g., `your-app.mojoauth.com`).
3. Configure the **Redirect URI** (e.g., `http://localhost:4200/auth/callback`).
4. Retrieve **Client ID**.
5. Enable your preferred authentication methods.

> **Note:** For SPAs, the recommended flow is **Authorization Code with PKCE** (no Client Secret required on the front-end).

### Step 2: Modify the Existing Angular Project

#### Substep 2.1: Install Dependencies

```bash
npm install angular-auth-oidc-client
```

#### Substep 2.2: Configure OIDC Module

Register the OIDC module in your `app.config.ts` (standalone) or `app.module.ts`:

```typescript
// app.config.ts (Standalone API - Angular 15+)
import { ApplicationConfig } from '@angular/core';
import { provideRouter } from '@angular/router';
import { provideAuth, LogLevel } from 'angular-auth-oidc-client';
import { routes } from './app.routes';

export const appConfig: ApplicationConfig = {
  providers: [
    provideRouter(routes),
    provideAuth({
      config: {
        authority: 'https://your-app.mojoauth.com', // Your MojoAuth Domain
        redirectUrl: 'http://localhost:4200/auth/callback',
        postLogoutRedirectUri: 'http://localhost:4200/',
        clientId: 'your_client_id',
        scope: 'openid profile email',
        responseType: 'code',
        silentRenew: true,
        useRefreshToken: true,
        logLevel: LogLevel.Debug,
      },
    }),
  ],
};
```

#### Substep 2.3: Configure Environment

Create environment files for your configuration (e.g., `src/environments/environment.ts`):

```typescript
// src/environments/environment.ts
export const environment = {
  production: false,
  mojoauth: {
    domain: 'your-app.mojoauth.com',
    clientId: 'your_client_id',
    redirectUri: 'http://localhost:4200/auth/callback',
  },
};
```

#### Substep 2.4: Create Auth Service

Create a dedicated authentication service (e.g., `src/app/services/auth.service.ts`):

```typescript
// src/app/services/auth.service.ts
import { Injectable } from '@angular/core';
import { OidcSecurityService } from 'angular-auth-oidc-client';
import { Observable } from 'rxjs';

@Injectable({ providedIn: 'root' })
export class AuthService {
  constructor(private oidcService: OidcSecurityService) {}

  get isAuthenticated$(): Observable<boolean> {
    return new Observable((observer) => {
      this.oidcService.isAuthenticated$.subscribe(({ isAuthenticated }) => {
        observer.next(isAuthenticated);
      });
    });
  }

  get userData$() {
    return this.oidcService.userData$;
  }

  login(): void {
    // Redirect to MojoAuth Hosted Login Page
    this.oidcService.authorize();
  }

  logout(): void {
    this.oidcService.logoff();
  }

  checkAuth(): Observable<any> {
    return this.oidcService.checkAuth();
  }
}
```

#### Substep 2.5: Update Login Page/UI

Since MojoAuth handles all authentication on its Hosted Login Page, your login component only needs a **"Sign In" button**:

```typescript
// src/app/login/login.component.ts
import { Component } from '@angular/core';
import { AuthService } from '../services/auth.service';

@Component({
  selector: 'app-login',
  standalone: true,
  template: `
    <div class="login-container">
      <h1>Welcome</h1>
      <p>Sign in with your preferred method — passwordless, social login, or passkeys.</p>

      <button (click)="handleLogin()">
        Sign In with MojoAuth
      </button>

      <p class="powered-by">Powered by MojoAuth — Passwordless Authentication</p>
    </div>
  `,
})
export class LoginComponent {
  constructor(private authService: AuthService) {}

  handleLogin(): void {
    this.authService.login();
  }
}
```

#### Substep 2.6: Create Callback Component

Create a callback component to handle the OIDC redirect (e.g., `src/app/auth/callback.component.ts`):

```typescript
// src/app/auth/callback.component.ts
import { Component, OnInit } from '@angular/core';
import { Router } from '@angular/router';
import { OidcSecurityService } from 'angular-auth-oidc-client';

@Component({
  selector: 'app-auth-callback',
  standalone: true,
  template: `<p>Authenticating...</p>`,
})
export class AuthCallbackComponent implements OnInit {
  constructor(
    private oidcService: OidcSecurityService,
    private router: Router
  ) {}

  ngOnInit(): void {
    this.oidcService.checkAuth().subscribe(({ isAuthenticated, userData }) => {
      if (isAuthenticated) {
        console.log('Authenticated User:', userData);
        this.router.navigate(['/dashboard']);
      } else {
        this.router.navigate(['/'], { queryParams: { error: 'auth_failed' } });
      }
    });
  }
}
```

#### Substep 2.7: Configure Routes

Update your `app.routes.ts` to include the callback route:

```typescript
// app.routes.ts
import { Routes } from '@angular/router';
import { LoginComponent } from './login/login.component';
import { AuthCallbackComponent } from './auth/callback.component';
import { DashboardComponent } from './dashboard/dashboard.component';

export const routes: Routes = [
  { path: '', component: LoginComponent },
  { path: 'auth/callback', component: AuthCallbackComponent },
  { path: 'dashboard', component: DashboardComponent },
];
```

### Step 3: Test the Implementation

1. Start your application: `ng serve`.
2. Navigate to `http://localhost:4200/`.
3. Click **"Sign In with MojoAuth"**.
4. You should be redirected to the MojoAuth Hosted Login Page.
5. Authenticate using any available method.
6. After successful authentication, you should be redirected back to `/auth/callback` and then to `/dashboard`.

## 3. Additional Considerations

- **Error Handling**: Subscribe to `OidcSecurityService` events to handle specific OIDC errors gracefully.
- **Styling**: Adapt the example template to match your application's design system (e.g., Angular Material).
- **Security**: Since this is a SPA, **PKCE** is automatically handled by `angular-auth-oidc-client`. Never store a Client Secret in the front-end.
- **Route Guards**: Use `AutoLoginPartialRoutesGuard` from the library to protect routes that require authentication.

## 4. Support

- **MojoAuth Documentation**: [mojoauth.com/docs](https://mojoauth.com/docs)
- **Check browser console**: Use browser developer tools to debug OIDC flow issues.
- **Library Documentation**: Refer to the [angular-auth-oidc-client documentation](https://github.com/damienbod/angular-auth-oidc-client) for advanced configuration.

```

oidc-hosted-page | SkillHub