# 01. G6 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


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://wiki.gen6.life/developer-resources/sdk-and-tooling/g6-mw-and-chain-api-guide/01.-g6-mw-authentication.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
