discord / embedded-app-sdk

🚀 The Discord Embedded App SDK lets you build rich, multiplayer experiences as Activities inside Discord.
https://discord.com/developers/docs/activities/overview
MIT License
1.22k stars 169 forks source link

Help getting my client to talk to my backend with CSP #240

Open erikthe-viking opened 1 month ago

erikthe-viking commented 1 month ago

Im trying to get my app ported to Discord. My frontend is showing up but i cant get my backend to bypass the CSP. My system is running on docker containers . Do you think nginx is causing these problems? Ive spent all weekend trying to get this to work so any help would be greatly appreciated. H

Heres my stack: Django, Create React APP, Ngnix, Docker

Docker compose file:

`version: '3.8'

services:
  db:
    container_name: database
    image: postgis/postgis:12-3.3
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U myuser -d mydb"]
      interval: 10s
      timeout: 10s
      retries: 5
    volumes:
      - ./postgres-data:/var/lib/postgresql/data
      #- postgres_data:/var/lib/postgresql/data
    environment:
      - POSTGRES_USER=myuser
      - POSTGRES_PASSWORD=mypassword
      - POSTGRES_DB=mydb
    networks:
      - mynetwork
  backend:
    container_name: backend
    image: backend-image
    build:
      context: ./backend
      dockerfile: DockerFile.dev.backend
    ports:
      - "8000:8000"
    depends_on:
      db:
        condition: service_healthy
    environment:
      - DEBUG=True # Change in production
      - DB_HOST=db
      - DB_PORT=5432
      # Add other environment variables needed for your Django app
    volumes:
      - ./backend:/app
    networks:
      - mynetwork

  frontend:
    container_name: frontend
    image: frontend-image
    build:
      context: ./frontend
      dockerfile: DockerFile.frontend
    ports:
      - "3000:3000"
    depends_on:
      - backend
    volumes:
      - ./frontend:/app
      - /app/node_modules
    networks:
      - mynetwork

  nginx:
    container_name: reverse-proxy-nginx
    image: nginx-image
    build:
      context: ./Nginx/
      dockerfile: DockerFile.dev.nginx
    ports:
      - "80:80"
    depends_on:
      - frontend
    networks:
      - mynetwork

volumes:
  postgres_data:

networks:
  mynetwork:
    driver: bridge`

    NGINX

    `http {
    upstream frontend {
        server frontend:3000;
    }

    upstream backend {
        server backend:8000;
    }

    server {
        listen 80;

        location / {
            # Assuming the frontend handles routing and all URIs should be sent to the frontend
            proxy_pass http://frontend;
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        }

        location /api/ {
            # Assuming all backend requests start with /api/
            proxy_pass http://backend;
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        }
    }
}

events {
    worker_connections 1024;
}`

index.js


`import React, { useState, useEffect } from 'react';
import ReactDOM from 'react-dom/client';
import { BrowserRouter as Router } from 'react-router-dom';
import { DiscordSDK, patchUrlMappings } from "@discord/embedded-app-sdk";
import './index.css';
import * as serviceWorker from './serviceWorker';
import 'bootstrap/dist/css/bootstrap.min.css';
import { AuthProvider } from './AuthContext';
import { GoogleOAuthProvider } from '@react-oauth/google';
import App from './app';
import { getApiUrl } from './config/config';

const isProd = process.env.NODE_ENV === 'production';

const DiscordApp = () => {
  const [isSDKReady, setIsSDKReady] = useState(false);
  const [auth, setAuth] = useState(null);
  const [isDiscordEnvironment, setIsDiscordEnvironment] = useState(false);

  useEffect(() => {
    const setupEnvironment = async () => {
      const urlParams = new URLSearchParams(window.location.search);
      const frameId = urlParams.get('frame_id');
      setIsDiscordEnvironment(!!frameId);

      if (isProd && isDiscordEnvironment) {
        await patchUrlMappings([
          { prefix: '/api', target: 'tunnel.clearedgear.com/api' }
        ]);
      }

      if (frameId) {
        const discordSdk = new DiscordSDK(process.env.REACT_APP_DISCORD_CLIENT_ID);

        try {
          await discordSdk.ready();
          console.log("Discord SDK is ready");

          const { code } = await discordSdk.commands.authorize({
            client_id: process.env.REACT_APP_DISCORD_CLIENT_ID,
            response_type: "code",
            state: "",
            prompt: "none",
            scope: ["identify", "guilds"],
          });

          const tokenExchangeUrl = getApiUrl('/discord/token');

          const response = await fetch(tokenExchangeUrl, {
            method: "POST",
            headers: {
              "Content-Type": "application/json",
            },
            body: JSON.stringify({ code }),
          });

          if (!response.ok) {
            throw new Error(`HTTP error! status: ${response.status}`);
          }

          const { access_token } = await response.json();

          const authResult = await discordSdk.commands.authenticate({ access_token });

          if (authResult == null) {
            throw new Error("Authenticate command failed");
          }

          setAuth(authResult);
          console.log("Discord SDK is authenticated");
        } catch (error) {
          console.error("Error setting up Discord SDK:", error);
        }
      }

      setIsSDKReady(true);
    };

    setupEnvironment();
  }, []);

  if (!isSDKReady) {
    return <div>Loading...</div>;
  }

  return (
    <Router>
      <React.StrictMode>
        <GoogleOAuthProvider clientId={process.env.REACT_APP_GOOGLE_CLIENT_ID}>
          <AuthProvider>
            <App discordAuth={auth} isDiscordEnvironment={isDiscordEnvironment} />
          </AuthProvider>
        </GoogleOAuthProvider>
      </React.StrictMode>
    </Router>
  );
};

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<DiscordApp />);

serviceWorker.unregister();`
matthova commented 1 month ago

Have you set up url mappings for your app via the dev portal?

https://discord.com/developers/docs/activities/development-guides#url-mapping