> ## Documentation Index
> Fetch the complete documentation index at: https://docs.strikebet.app/llms.txt
> Use this file to discover all available pages before exploring further.

# Generate Link

> Generate authentication links for users (admin only)

Generate secure authentication links for users. This endpoint allows administrators to create magic links, recovery links, or invitation links that can be sent to users via custom channels.

<Warning>
  This endpoint requires service role authentication. Only use the service role key on your backend servers, never in client-side code.
</Warning>

<RequestExample>
  ```bash cURL
  curl -X POST "http://localhost:8080/admin/generate_link" \
    -H "Authorization: Bearer service_role_key_here" \
    -H "Content-Type: application/json" \
    -d '{
      "type": "magiclink",
      "email": "user@example.com",
      "redirect_to": "https://yourapp.com/dashboard"
    }'
  ```

  ```javascript JavaScript
  const response = await fetch('http://localhost:8080/admin/generate_link', {
    method: 'POST',
    headers: {
      'Authorization': 'Bearer service_role_key_here',
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      type: 'magiclink',
      email: 'user@example.com',
      redirect_to: 'https://yourapp.com/dashboard'
    }),
  });

  const linkData = await response.json();
  ```

  ```python Python
  import requests

  headers = {
      'Authorization': 'Bearer service_role_key_here',
      'Content-Type': 'application/json'
  }

  data = {
      "type": "magiclink",
      "email": "user@example.com",
      "redirect_to": "https://yourapp.com/dashboard"
  }

  response = requests.post(
      'http://localhost:8080/admin/generate_link',
      headers=headers,
      json=data
  )
  link_data = response.json()
  ```

  ```go Go
  package main

  import (
      "bytes"
      "encoding/json"
      "net/http"
  )

  func main() {
      data := map[string]string{
          "type":        "magiclink",
          "email":       "user@example.com",
          "redirect_to": "https://yourapp.com/dashboard",
      }
      
      jsonData, _ := json.Marshal(data)
      
      req, _ := http.NewRequest("POST", 
          "http://localhost:8080/admin/generate_link", 
          bytes.NewBuffer(jsonData))
      req.Header.Set("Authorization", "Bearer service_role_key_here")
      req.Header.Set("Content-Type", "application/json")
      
      client := &http.Client{}
      resp, err := client.Do(req)
      // Handle response...
  }
  ```
</RequestExample>

## Request Body

<ParamField body="type" type="string" required>
  The type of link to generate.

  **Options:**

  * `signup` - Email confirmation link for new users
  * `magiclink` - Passwordless authentication link
  * `recovery` - Password recovery link
  * `invite` - User invitation link
  * `email_change` - Email change confirmation link
</ParamField>

<ParamField body="email" type="string" required>
  Email address of the user for whom to generate the link.
</ParamField>

<ParamField body="redirect_to" type="string">
  URL to redirect to after the link is used. If not provided, uses the default redirect URL.
</ParamField>

<ParamField body="data" type="object">
  Additional data to include with the link (for invitations or user creation).
</ParamField>

<ParamField body="password" type="string">
  Password for the user (required for some link types like recovery).
</ParamField>

## Response

<ResponseField name="action_link" type="string">
  The generated authentication link that can be sent to the user
</ResponseField>

<ResponseField name="email_otp" type="string">
  One-time password for email verification (when applicable)
</ResponseField>

<ResponseField name="hashed_token" type="string">
  Hashed version of the token for verification purposes
</ResponseField>

<ResponseField name="verification_type" type="string">
  Type of verification this link performs
</ResponseField>

<ResponseField name="redirect_to" type="string">
  The redirect URL that will be used after verification
</ResponseField>

<ResponseExample>
  ```json 200 - Link Generated Successfully
  {
    "action_link": "http://localhost:8080/verify?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...&type=magiclink&redirect_to=https%3A//yourapp.com/dashboard",
    "email_otp": "123456",
    "hashed_token": "sha256_hash_of_token",
    "verification_type": "magiclink",
    "redirect_to": "https://yourapp.com/dashboard"
  }
  ```
</ResponseExample>

## Error Responses

<ResponseExample>
  ```json 400 - Invalid Request
  {
    "code": 400,
    "msg": "Invalid link type",
    "details": "Link type must be one of: signup, magiclink, recovery, invite, email_change"
  }
  ```

  ```json 401 - Unauthorized
  {
    "code": 401,
    "msg": "Invalid service role key",
    "details": "Please provide a valid service role key"
  }
  ```

  ```json 404 - User Not Found
  {
    "code": 404,
    "msg": "User not found",
    "details": "No user found with the provided email address"
  }
  ```
</ResponseExample>

## Link Types

### Magic Link

Generate a passwordless authentication link:

```json
{
  "type": "magiclink",
  "email": "user@example.com",
  "redirect_to": "https://yourapp.com/dashboard"
}
```

### Password Recovery Link

Generate a password recovery link:

```json
{
  "type": "recovery",
  "email": "user@example.com",
  "redirect_to": "https://yourapp.com/reset-password"
}
```

### Email Confirmation Link

Generate an email confirmation link for new users:

```json
{
  "type": "signup",
  "email": "newuser@example.com",
  "redirect_to": "https://yourapp.com/welcome"
}
```

### User Invitation Link

Generate an invitation link for new users:

```json
{
  "type": "invite",
  "email": "invite@example.com",
  "data": {
    "first_name": "John",
    "last_name": "Doe",
    "role": "team_member"
  },
  "redirect_to": "https://yourapp.com/setup"
}
```

### Email Change Confirmation

Generate a link to confirm email address changes:

```json
{
  "type": "email_change",
  "email": "newemail@example.com",
  "redirect_to": "https://yourapp.com/profile"
}
```

## Implementation Examples

### React Admin Link Generator

```jsx
import { useState } from 'react';

function AdminLinkGenerator() {
  const [linkType, setLinkType] = useState('magiclink');
  const [email, setEmail] = useState('');
  const [redirectTo, setRedirectTo] = useState('');
  const [loading, setLoading] = useState(false);
  const [generatedLink, setGeneratedLink] = useState('');
  const [error, setError] = useState('');

  const handleGenerate = async (e) => {
    e.preventDefault();
    setLoading(true);
    setError('');
    setGeneratedLink('');

    try {
      const response = await fetch('/api/admin/generate_link', {
        method: 'POST',
        headers: {
          'Authorization': `Bearer ${process.env.REACT_APP_SERVICE_ROLE_KEY}`,
          'Content-Type': 'application/json',
        },
        body: JSON.stringify({
          type: linkType,
          email,
          redirect_to: redirectTo || undefined
        }),
      });

      if (!response.ok) {
        const errorData = await response.json();
        throw new Error(errorData.msg || 'Failed to generate link');
      }

      const linkData = await response.json();
      setGeneratedLink(linkData.action_link);
      
    } catch (err) {
      setError(err.message);
    } finally {
      setLoading(false);
    }
  };

  const copyToClipboard = async () => {
    try {
      await navigator.clipboard.writeText(generatedLink);
      alert('Link copied to clipboard!');
    } catch (err) {
      console.error('Failed to copy link:', err);
    }
  };

  return (
    <div className="admin-link-generator">
      <h2>Generate Authentication Link</h2>
      
      {error && (
        <div className="error-message">
          {error}
        </div>
      )}

      <form onSubmit={handleGenerate} className="link-form">
        <div className="form-group">
          <label htmlFor="linkType">Link Type</label>
          <select
            id="linkType"
            value={linkType}
            onChange={(e) => setLinkType(e.target.value)}
            required
          >
            <option value="magiclink">Magic Link</option>
            <option value="recovery">Password Recovery</option>
            <option value="signup">Email Confirmation</option>
            <option value="invite">User Invitation</option>
            <option value="email_change">Email Change</option>
          </select>
        </div>

        <div className="form-group">
          <label htmlFor="email">Email Address</label>
          <input
            type="email"
            id="email"
            value={email}
            onChange={(e) => setEmail(e.target.value)}
            placeholder="user@example.com"
            required
          />
        </div>

        <div className="form-group">
          <label htmlFor="redirectTo">Redirect URL (optional)</label>
          <input
            type="url"
            id="redirectTo"
            value={redirectTo}
            onChange={(e) => setRedirectTo(e.target.value)}
            placeholder="https://yourapp.com/dashboard"
          />
        </div>

        <button type="submit" disabled={loading}>
          {loading ? 'Generating...' : 'Generate Link'}
        </button>
      </form>

      {generatedLink && (
        <div className="generated-link">
          <h3>Generated Link</h3>
          <div className="link-container">
            <input
              type="text"
              value={generatedLink}
              readOnly
              className="link-input"
            />
            <button onClick={copyToClipboard} className="copy-button">
              Copy
            </button>
          </div>
          <p className="link-info">
            This link will expire in 1 hour and can only be used once.
          </p>
        </div>
      )}
    </div>
  );
}

export default AdminLinkGenerator;
```

### Bulk Link Generation

```jsx
import { useState } from 'react';

function BulkLinkGenerator() {
  const [emails, setEmails] = useState('');
  const [linkType, setLinkType] = useState('invite');
  const [redirectTo, setRedirectTo] = useState('');
  const [loading, setLoading] = useState(false);
  const [results, setResults] = useState([]);

  const handleBulkGenerate = async (e) => {
    e.preventDefault();
    setLoading(true);
    setResults([]);

    const emailList = emails.split('\n').filter(email => email.trim());
    const generatedLinks = [];

    for (const email of emailList) {
      try {
        const response = await fetch('/api/admin/generate_link', {
          method: 'POST',
          headers: {
            'Authorization': `Bearer ${process.env.REACT_APP_SERVICE_ROLE_KEY}`,
            'Content-Type': 'application/json',
          },
          body: JSON.stringify({
            type: linkType,
            email: email.trim(),
            redirect_to: redirectTo || undefined
          }),
        });

        if (response.ok) {
          const linkData = await response.json();
          generatedLinks.push({
            email: email.trim(),
            success: true,
            link: linkData.action_link
          });
        } else {
          const errorData = await response.json();
          generatedLinks.push({
            email: email.trim(),
            success: false,
            error: errorData.msg
          });
        }
      } catch (err) {
        generatedLinks.push({
          email: email.trim(),
          success: false,
          error: err.message
        });
      }
    }

    setResults(generatedLinks);
    setLoading(false);
  };

  const exportResults = () => {
    const csvContent = [
      'Email,Status,Link,Error',
      ...results.map(result => 
        `${result.email},${result.success ? 'Success' : 'Failed'},${result.link || ''},${result.error || ''}`
      )
    ].join('\n');

    const blob = new Blob([csvContent], { type: 'text/csv' });
    const url = window.URL.createObjectURL(blob);
    const a = document.createElement('a');
    a.href = url;
    a.download = `bulk_links_${Date.now()}.csv`;
    a.click();
    window.URL.revokeObjectURL(url);
  };

  return (
    <div className="bulk-link-generator">
      <h2>Bulk Link Generation</h2>
      
      <form onSubmit={handleBulkGenerate} className="bulk-form">
        <div className="form-group">
          <label htmlFor="emails">Email Addresses (one per line)</label>
          <textarea
            id="emails"
            value={emails}
            onChange={(e) => setEmails(e.target.value)}
            placeholder="user1@example.com&#10;user2@example.com&#10;user3@example.com"
            rows={10}
            required
          />
        </div>

        <div className="form-group">
          <label htmlFor="linkType">Link Type</label>
          <select
            id="linkType"
            value={linkType}
            onChange={(e) => setLinkType(e.target.value)}
          >
            <option value="invite">User Invitation</option>
            <option value="magiclink">Magic Link</option>
            <option value="recovery">Password Recovery</option>
            <option value="signup">Email Confirmation</option>
          </select>
        </div>

        <div className="form-group">
          <label htmlFor="redirectTo">Redirect URL (optional)</label>
          <input
            type="url"
            id="redirectTo"
            value={redirectTo}
            onChange={(e) => setRedirectTo(e.target.value)}
            placeholder="https://yourapp.com/welcome"
          />
        </div>

        <button type="submit" disabled={loading}>
          {loading ? 'Generating Links...' : 'Generate All Links'}
        </button>
      </form>

      {results.length > 0 && (
        <div className="results">
          <div className="results-header">
            <h3>Results ({results.length} total)</h3>
            <button onClick={exportResults} className="export-button">
              Export CSV
            </button>
          </div>
          
          <div className="results-summary">
            <span className="success-count">
              ✅ {results.filter(r => r.success).length} successful
            </span>
            <span className="error-count">
              ❌ {results.filter(r => !r.success).length} failed
            </span>
          </div>

          <div className="results-list">
            {results.map((result, index) => (
              <div key={index} className={`result-item ${result.success ? 'success' : 'error'}`}>
                <div className="result-email">{result.email}</div>
                {result.success ? (
                  <div className="result-link">
                    <input type="text" value={result.link} readOnly />
                    <button onClick={() => navigator.clipboard.writeText(result.link)}>
                      Copy
                    </button>
                  </div>
                ) : (
                  <div className="result-error">{result.error}</div>
                )}
              </div>
            ))}
          </div>
        </div>
      )}
    </div>
  );
}

export default BulkLinkGenerator;
```

### Node.js Backend Handler

```javascript
const express = require('express');
const { body, validationResult } = require('express-validator');

const router = express.Router();

// Middleware to verify service role
const verifyServiceRole = (req, res, next) => {
  const authHeader = req.headers.authorization;
  const token = authHeader?.split(' ')[1];

  if (!token || token !== process.env.SERVICE_ROLE_KEY) {
    return res.status(401).json({
      code: 401,
      msg: 'Invalid service role key',
      details: 'Please provide a valid service role key'
    });
  }

  next();
};

router.post('/admin/generate_link', [
  verifyServiceRole,
  body('type').isIn(['signup', 'magiclink', 'recovery', 'invite', 'email_change']),
  body('email').isEmail().normalizeEmail(),
  body('redirect_to').optional().isURL(),
  body('data').optional().isObject()
], async (req, res) => {
  try {
    // Check validation errors
    const errors = validationResult(req);
    if (!errors.isEmpty()) {
      return res.status(400).json({
        code: 400,
        msg: 'Invalid request data',
        details: errors.array()
      });
    }

    const { type, email, redirect_to, data, password } = req.body;

    // Call Strike Auth Service
    const response = await fetch(`${process.env.AUTH_SERVICE_URL}/admin/generate_link`, {
      method: 'POST',
      headers: {
        'Authorization': `Bearer ${process.env.SERVICE_ROLE_KEY}`,
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({
        type,
        email,
        redirect_to,
        data,
        password
      }),
    });

    const result = await response.json();

    if (!response.ok) {
      return res.status(response.status).json(result);
    }

    // Log link generation
    console.log(`Link generated: ${type} for ${email}`);

    res.json(result);

  } catch (error) {
    console.error('Link generation error:', error);
    res.status(500).json({
      code: 500,
      msg: 'Internal server error',
      details: 'Please try again later'
    });
  }
});

module.exports = router;
```

## Use Cases

### Custom Email Templates

Generate links for use in custom email templates:

```javascript
async function sendCustomInvitation(email, userData) {
  // Generate invitation link
  const linkResponse = await fetch('/api/admin/generate_link', {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${process.env.SERVICE_ROLE_KEY}`,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      type: 'invite',
      email,
      data: userData,
      redirect_to: 'https://yourapp.com/welcome'
    }),
  });

  const { action_link } = await linkResponse.json();

  // Send custom email with the generated link
  await sendEmail({
    to: email,
    subject: 'Welcome to Strike!',
    template: 'custom-invitation',
    data: {
      inviteLink: action_link,
      userData
    }
  });
}
```

### Integration with External Systems

Generate links for integration with CRM or marketing tools:

```javascript
async function syncUserWithCRM(userData) {
  // Generate magic link for user
  const linkResponse = await fetch('/api/admin/generate_link', {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${process.env.SERVICE_ROLE_KEY}`,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      type: 'magiclink',
      email: userData.email,
      redirect_to: 'https://yourapp.com/dashboard'
    }),
  });

  const { action_link } = await linkResponse.json();

  // Update CRM with login link
  await updateCRMContact(userData.email, {
    login_link: action_link,
    last_updated: new Date().toISOString()
  });
}
```

## Security Considerations

* **Service Role Protection**: Never expose service role keys in client-side code
* **Link Expiration**: Generated links expire after 1 hour by default
* **Single Use**: Links can only be used once for security
* **Rate Limiting**: Implement rate limits for link generation
* **Audit Logging**: Log all link generation activities

## Best Practices

<AccordionGroup>
  <Accordion title="Link Management">
    * Generate links only when needed
    * Use appropriate link types for different use cases
    * Include meaningful redirect URLs
    * Track link usage and expiration
  </Accordion>

  <Accordion title="Security">
    * Validate all input parameters
    * Use HTTPS for all redirect URLs
    * Implement proper access controls
    * Monitor for suspicious link generation patterns
  </Accordion>

  <Accordion title="User Experience">
    * Provide clear instructions with generated links
    * Use descriptive redirect URLs
    * Handle expired links gracefully
    * Offer alternative authentication methods
  </Accordion>
</AccordionGroup>

## Testing

### Unit Tests

```javascript
describe('POST /admin/generate_link', () => {
  test('should generate magic link for existing user', async () => {
    const response = await request(app)
      .post('/admin/generate_link')
      .set('Authorization', 'Bearer valid_service_role_key')
      .send({
        type: 'magiclink',
        email: 'existing@example.com',
        redirect_to: 'https://example.com/dashboard'
      })
      .expect(200);

    expect(response.body.action_link).toContain('verify?token=');
    expect(response.body.verification_type).toBe('magiclink');
  });

  test('should generate invitation link with user data', async () => {
    const response = await request(app)
      .post('/admin/generate_link')
      .set('Authorization', 'Bearer valid_service_role_key')
      .send({
        type: 'invite',
        email: 'new@example.com',
        data: { first_name: 'John', role: 'admin' }
      })
      .expect(200);

    expect(response.body.action_link).toBeDefined();
  });

  test('should reject invalid service role', async () => {
    await request(app)
      .post('/admin/generate_link')
      .set('Authorization', 'Bearer invalid_key')
      .send({
        type: 'magiclink',
        email: 'test@example.com'
      })
      .expect(401);
  });
});
```

## Related Endpoints

<CardGroup cols={2}>
  <Card title="Create User" icon="user-plus" href="/api-reference/admin/create-user">
    Create new user accounts
  </Card>

  <Card title="Update User" icon="user-edit" href="/api-reference/admin/update-user">
    Update user information
  </Card>

  <Card title="Invite User" icon="paper-plane" href="/api-reference/admin/invite-user">
    Send user invitations
  </Card>

  <Card title="Verify Link" icon="check" href="/api-reference/authentication/verify-get">
    Verify generated links
  </Card>
</CardGroup>
