> For the complete documentation index, see [llms.txt](https://wiki.gen6.life/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://wiki.gen6.life/technology-core/developer-resources/sdk-and-tooling/gen6-mw-and-chain-api-guide/01.-gen6-mw-authentication.md).

# 01. Gen6 MW Authentication

## Authentication

Gen6 dApps uses a **two-tier authentication system** combining blockchain wallet signatures with JWT tokens for secure API access (all provided through G6 MW instance(s)).

### Overview

Authentication requires:

1. **Polkadot Wallet** - User must have a connected wallet (via extension or Google auth)
2. **JWT Token** - User must sign a challenge to prove wallet ownership

The JWT token is stored in an HttpOnly cookie and included automatically in all API requests.

### Authentication Flow

#### Step 1: Get Challenge

Request a signing challenge from the backend.

**Endpoint**: `POST /auth/challenge`

**Request**:

```typescript
const response = await fetch(`${apiUrl}/auth/challenge`, {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  credentials: 'include',
  body: JSON.stringify({
    public_address: g6_address // SS58-355 encoded address
  })
})

const data = await response.json()
```

**Request Body**:

```typescript
interface ChallengeRequest {
  public_address: string // SS58-355 encoded Gen6 address
}
```

**Response**:

```typescript
interface ChallengeResponse {
  challenge: string // Random challenge string to sign
}
```

**Example**:

```json
{
  "challenge": "7f8a9b3c..."
}
```

***

#### Step 2: Sign Challenge

Sign the challenge using the Polkadot wallet.

**Implementation**:

```typescript
import { getSigner } from '@/packages/auth/lib/signer'

// Get signer based on authentication method
const signerResult = await getSigner(
  authMethod,
  authState.walletAddress,
  authState.googleAccessToken,
  api
)

if (!signerResult.signer.signRaw) {
  throw new Error('signRaw is not available on the signer')
}

// Sign the challenge
const signature = await signerResult.signer.signRaw({
  address: g6_address,
  data: challenge,
  type: 'bytes'
})

const signedChallenge = signature.signature
```

***

#### Step 3: Verify Signature

Send the signed challenge to verify and obtain a JWT token.

**Endpoint**: `POST /auth/verify`

**Request**:

```typescript
const response = await fetch(`${apiUrl}/auth/verify`, {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  credentials: 'include',
  body: JSON.stringify({
    public_address: g6_address,
    signature: signature,
    origin: authMethod === 'google' ? 'google' : 'native'
  })
})
```

**Request Body**:

```typescript
interface VerifyRequest {
  public_address: string // SS58-355 encoded address
  signature: string // Hex-encoded signature from wallet
  origin: string // 'google' or 'native' (auth method identifier)
}
```

**Response**:

* Sets HttpOnly cookie with JWT token
* Returns success status

**Cookie Details**:

* Name: Session cookie (managed by backend)
* HttpOnly: `true` (not accessible via JavaScript)
* Secure: `true` (HTTPS only in production)
* SameSite: `Lax`

***

#### Step 4: Verify Authentication Status

Check if the current user is authenticated.

**Endpoint**: `GET /auth/jwt_ping`

**Implementation**:

```typescript
import axiosInstance from '@/packages/auth/api/axiosInstance'

export const queryJWTPing = async () => {
  const response = await axiosInstance.get('/auth/jwt_ping')
  return response.data
}
```

**Response**:

The response structure depends on the backend implementation. Check the actual response format returned by the backend.

**Usage in React**:

```typescript
import useIsAuthenticated from '@/packages/auth/hooks/useIsAuthenticated'

function Component() {
  const { isAuthenticated } = useIsAuthenticated()

  if (!isAuthenticated) return <div>Please log in</div>

  return <div>Welcome!</div>
}
```

**Query Configuration**:

```typescript
useQuery({
  queryKey: ['jwtPing', g6_address],
  queryFn: queryJWTPing,
  enabled: !!g6_address && hasAuthMethod,
  retry: false,
  staleTime: 5 * 60 * 1000, // 5 minutes
  gcTime: 10 * 60 * 1000,
  refetchOnWindowFocus: true,
  refetchOnReconnect: true
})
```

***

### Faucet

Request test tokens from the faucet.

**Endpoint**: `POST /faucet/request`

**Requirements**:

* Authenticated user (JWT token in HttpOnly cookie)

**Request**:

```typescript
const response = await fetch(`${getApiUrl()}/faucet/request`, {
  method: 'POST',
  credentials: 'include'
})
```

**Response**:

```typescript
interface FaucetResponse {
  success: boolean
  tx_hash?: string
  amount?: string
}
```

**Note**: Faucet is automatically called after successful authentication for Google auth users.

***

### Route Guards

Protect routes with authentication checks.

**Pattern**:

```typescript
import { createFileRoute } from '@tanstack/react-router'
import { useGen6 } from 'gen6-context'
import { useIsAuthenticated } from '@/packages/auth/hooks/useIsAuthenticated'
import { Unlogged } from '@/components/unlogged'
import { Unauthorized } from '@/components/unauthorized'

export const Route = createFileRoute('/protected-route')({
  component: RouteComponent
})

function RouteComponent() {
  const { currentAccount } = useGen6()
  const { isAuthenticated } = useIsAuthenticated()

  // First tier: Check wallet connection
  if (!currentAccount) {
    return <Unlogged />
  }

  // Second tier: Check JWT authentication
  if (!isAuthenticated) {
    return <Unauthorized />
  }

  // User is fully authenticated
  return <ProtectedPage />
}
```

***

### Complete Authentication Hook

The `useAuthorize` hook combines all authentication steps.

**Location**: src/packages/auth/hooks/useAuthorize.tsx

**Usage**:

```typescript
import useAuthorize from '@/packages/auth/hooks/useAuthorize'

function LoginButton() {
  const { authorize, isLoading } = useAuthorize((success) => {
      if (success) {
        toast.success('Successfully authenticated!')
      } else {
        toast.error('Authentication failed')
      }
  })

  // Trigger authorize when needed (e.g. implicitly or via button)
  const handleLogin = () => {
    authorize()
  }

  return (
    <button onClick={handleLogin} disabled={isLoading}>
      {isLoading ? 'Authenticating...' : 'Login'}
    </button>
  )
}
```

**Implementation Details**:

```typescript
export function useAuthorize(
  setAuthenticationStatus: (success: boolean) => void
) {
  const { currentAccount } = useGen6()

  const authorize = async () => {
    // 1. Get challenge
    // 2. Sign challenge (handles Google/Wallet differences)
    // 3. Verify signature
    // 4. Reset/Invalidate queries
    // 5. Call setAuthenticationStatus(true/false)
  }

  return { authorize, isLoading }
}
```

***

### Axios Configuration

All authenticated API calls use the centralized axios instance.

**Location**: src/packages/auth/api/axiosInstance.ts

**Configuration**:

```typescript
import axios from 'axios'
import { getApiUrl } from '@/data/nodes'

export const axiosInstance = axios.create({
  baseURL: getApiUrl(),
  headers: {
    'Content-Type': 'application/json'
  },
  withCredentials: true // Include cookies
})
```

***

### Security Best Practices

#### JWT Token Management

1. **HttpOnly cookies** - Tokens not accessible via JavaScript (XSS protection)
2. **Secure flag** - HTTPS only in production

***

### Common Issues

#### "Authentication failed"

* **Cause**: Wallet not connected or signature invalid
* **Solution**: Ensure wallet extension is installed and unlocked

#### "CORS error"

* **Cause**: Origin not whitelisted on backend
* **Solution**: Verify `origin` parameter matches backend whitelist

***

### Address Encoding

Gen6 uses **SS58 address format with prefix 355**.

**Conversion**:

```typescript
import { encodeAddress } from '@polkadot/util-crypto'

// Convert to Gen6 address format
const g6_address = encodeAddress(publicKey, 355)
```

**Example**:

```
Public Key: 0x1234...
Gen6 Address: g6x1234... (SS58-355)
```

Always use the Gen6-encoded address for API requests.

***

### Next Steps

* Identity Management - Create and manage user profiles
* Real-Seal - Sign documents and texts
* Ncrypt - Send encrypted messages
