Movatterモバイル変換


[0]ホーム

URL:


Skip to content
Search Gists
Sign in Sign up

Instantly share code, notes, and snippets.

@mizchi
CreatedOctober 9, 2025 11:49
    • Star(0)You must be signed in to star a gist
    • Fork(0)You must be signed in to fork a gist

    Select an option

    Save mizchi/ef846db49e8d8fade4c209445c7b0503 to your computer and use it in GitHub Desktop.
    /**
    Discord Auth for Cloudflare Access
    based on https://github.com/Erisa/discord-oidc-worker
    # Create discord application
    - Get client id and secret
    - Set redirect URL to `https://<cloudflare-name>.cloudflareaccess.com/cdn-cgi/access/callback`
    # Set oidc.json
    oidc.json
    {
    "clientId": "<discord-client-id>",
    "clientSecret": "<discord-secret>",
    "redirectURL": "https://<cloudflare-name>.cloudflareaccess.com/cdn-cgi/access/callback",
    "serversToCheckRolesFor": ["<discord-server-id-to-check>"]
    }
    # Wrangler with KV
    ```
    $ npx wrangler kv:namespace create discord-popopo-keys
    ```
    wrangler.json
    {
    "name": "discord-popopo-oidc",
    "compatibility_date": "2025-10-08",
    "main": "main.js",
    "kv_namespaces": [
    {
    "binding": "KV",
    "id": "<kv-namespace-id>"
    }
    ]
    }
    deploy `wrangler deploy`
    ## Cloudflare Access Settings
    - Cloudflare Access -> Application
    https://one.dash.cloudflare.com/<your-cf-id>/settings/authentication
    - Login method -> Add new -> OIDC
    - App ID => `<discord-client-id>`
    - Secret => `<discord-client-secret>`
    - Token URL => `<your-deployment-url>/token`
    - Auth URL => `<your-deployment-url>/authorize/guilds
    - Authorization URL => `<your-deployment-url>/token`
    - Certificate URL => `<your-deployment-url>/jwks.json`
    - PKCE => Enabled
    - OIDC Claims
    - id
    - email
    - discriminator
    - guilds
    Auth user
    - Compute(Workers) -> [Worker]
    - Settings -> Domain & Routes -> Cloudflare Access
    */
    importconfigfrom"./oidc.json"with{type:"json"};
    import{Hono}from"hono";
    import*asjosefrom"jose";
    constalgorithm={
    name:"RSASSA-PKCS1-v1_5",
    modulusLength:2048,
    publicExponent:newUint8Array([0x01,0x00,0x01]),
    hash:{name:"SHA-256"},
    };
    constimportAlgo={
    name:"RSASSA-PKCS1-v1_5",
    hash:{name:"SHA-256"},
    };
    asyncfunctionloadOrGenerateKeyPair(KV){
    letkeyPair={};
    letkeyPairJson=awaitKV.get("keys",{type:"json"});
    if(keyPairJson!==null){
    keyPair.publicKey=awaitcrypto.subtle.importKey(
    "jwk",
    keyPairJson.publicKey,
    importAlgo,
    true,
    ["verify"]
    );
    keyPair.privateKey=awaitcrypto.subtle.importKey(
    "jwk",
    keyPairJson.privateKey,
    importAlgo,
    true,
    ["sign"]
    );
    returnkeyPair;
    }else{
    keyPair=awaitcrypto.subtle.generateKey(algorithm,true,[
    "sign",
    "verify",
    ]);
    awaitKV.put(
    "keys",
    JSON.stringify({
    privateKey:awaitcrypto.subtle.exportKey("jwk",keyPair.privateKey),
    publicKey:awaitcrypto.subtle.exportKey("jwk",keyPair.publicKey),
    })
    );
    returnkeyPair;
    }
    }
    constapp=newHono();
    app.get("/authorize/:scopemode",async(c)=>{
    if(
    c.req.query("client_id")!==config.clientId||
    c.req.query("redirect_uri")!==config.redirectURL||
    !["guilds","email"].includes(c.req.param("scopemode"))
    ){
    returnc.text("Bad request.",400);
    }
    constparams=newURLSearchParams({
    client_id:config.clientId,
    redirect_uri:config.redirectURL,
    response_type:"code",
    scope:
    c.req.param("scopemode")=="guilds"
    ?"identify email guilds"
    :"identify email",
    state:c.req.query("state"),
    prompt:"none",
    }).toString();
    returnc.redirect("https://discord.com/oauth2/authorize?"+params);
    });
    app.post("/token",async(c)=>{
    constbody=awaitc.req.parseBody();
    constcode=body["code"];
    constparams=newURLSearchParams({
    client_id:config.clientId,
    client_secret:config.clientSecret,
    redirect_uri:config.redirectURL,
    code:code,
    grant_type:"authorization_code",
    scope:"identify email",
    }).toString();
    constr=awaitfetch("https://discord.com/api/v10/oauth2/token",{
    method:"POST",
    body:params,
    headers:{
    "Content-Type":"application/x-www-form-urlencoded",
    },
    }).then((res)=>res.json());
    if(r===null)returnnewResponse("Bad request.",{status:400});
    constuserInfo=awaitfetch("https://discord.com/api/v10/users/@me",{
    headers:{
    Authorization:"Bearer "+r["access_token"],
    },
    }).then((res)=>res.json());
    if(!userInfo["verified"])returnc.text("Bad request.",400);
    letservers=[];
    constserverResp=awaitfetch(
    "https://discord.com/api/v10/users/@me/guilds",
    {
    headers:{
    Authorization:"Bearer "+r["access_token"],
    },
    }
    );
    if(serverResp.status===200){
    constserverJson=awaitserverResp.json();
    servers=serverJson.map((item)=>{
    returnitem["id"];
    });
    }
    letroleClaims={};
    if(c.env.DISCORD_TOKEN&&"serversToCheckRolesFor"inconfig){
    awaitPromise.all(
    config.serversToCheckRolesFor.map(async(guildId)=>{
    if(servers.includes(guildId)){
    letmemberPromise=fetch(
    `https://discord.com/api/v10/guilds/${guildId}/members/${userInfo["id"]}`,
    {
    headers:{
    Authorization:"Bot "+c.env.DISCORD_TOKEN,
    },
    }
    );
    // i had issues doing this any other way?
    constmemberResp=awaitmemberPromise;
    constmemberJson=awaitmemberResp.json();
    roleClaims[`roles:${guildId}`]=memberJson.roles;
    }
    })
    );
    }
    letpreferred_username=userInfo["username"];
    if(userInfo["discriminator"]&&userInfo["discriminator"]!=="0"){
    preferred_username+=`#${userInfo["discriminator"]}`;
    }
    letdisplayName=userInfo["global_name"]??userInfo["username"];
    constidToken=awaitnewjose.SignJWT({
    iss:"https://cloudflare.com",
    aud:config.clientId,
    preferred_username,
    ...userInfo,
    ...roleClaims,
    email:userInfo["email"],
    global_name:userInfo["global_name"],
    name:displayName,
    guilds:servers,
    })
    .setProtectedHeader({alg:"RS256"})
    .setExpirationTime("1h")
    .setAudience(config.clientId)
    .sign((awaitloadOrGenerateKeyPair(c.env.KV)).privateKey);
    returnc.json({
    ...r,
    scope:"identify email",
    id_token:idToken,
    });
    });
    app.get("/jwks.json",async(c)=>{
    letpublicKey=(awaitloadOrGenerateKeyPair(c.env.KV)).publicKey;
    returnc.json({
    keys:[
    {
    alg:"RS256",
    kid:"jwtRS256",
    ...(awaitcrypto.subtle.exportKey("jwk",publicKey)),
    },
    ],
    });
    });
    exportdefaultapp;
    Sign up for freeto join this conversation on GitHub. Already have an account?Sign in to comment

    [8]ページ先頭

    ©2009-2025 Movatter.jp