Skip to content

Instantly share code, notes, and snippets.

@mryhryki
Last active December 17, 2024 00:52
Show Gist options
  • Save mryhryki/004c6c682520ec02436a9d0780c0d1a4 to your computer and use it in GitHub Desktop.
Save mryhryki/004c6c682520ec02436a9d0780c0d1a4 to your computer and use it in GitHub Desktop.

Issue M2M Token for Auth0

Prepare

  1. Setup Node.js (Required version >= 20)
  2. Clone this Gist
  3. Run npm install to install dependencies

Set Common Environment Variables

export AUTH0_DOMAIN="(your_domain.auth0.com)"
export AUTH0_CLIENT_ID="(your_client_id)"
export AUTH0_AUDIENCE="(your_audience)"

# Optional
export AUTH0_ORGANIZATION="(your_organization_id)"

[Pattern 1] Authentication Methods: Private Key JWT

# Set Environment Variables
export PUBLIC_KEY_ID="(your_public_key_id from Auth0)"
export PRIVATE_KEY_PEM="$(cat path/to/your/private-key.pem)"

# Run the script
npm run private-key-jwt

[Note] How to Generate a Key-Pair

# Private Key
openssl genrsa -out sample.pem 2048

# Public Key
openssl rsa -in sample.pem -outform PEM -pubout -out sample.pem.pub

[Pattern 2] Authentication Methods: Client Credential

# Set Environment Variables
export AUTH0_CLIENT_SECRET="(your_client_secret)"

# Run the script
npm run client-credential
*.pem*
node_modules
package-lock.json
temp/**
import { getEnv } from './common.js';
const main = async () => {
const auth0Domain = getEnv('AUTH0_DOMAIN');
const auth0ClientId = getEnv('AUTH0_CLIENT_ID');
const auth0ClientSecret = getEnv('AUTH0_CLIENT_SECRET');
const auth0Audience = getEnv('AUTH0_AUDIENCE');
const auth0Organization = getEnv('AUTH0_ORGANIZATION', false);
const response = await fetch(`https://${auth0Domain}/oauth/token`, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
audience: auth0Audience,
client_id: auth0ClientId,
client_secret: auth0ClientSecret,
grant_type: "client_credentials",
organization: auth0Organization,
}),
});
console.log(`[Response Status]\n${response.status}\n`);
const body = await response.text();
console.log(`[Response Body]\n${body}\n`);
const { access_token: accessToken } = JSON.parse(body);
console.log(`[Access Token]\n${accessToken}\n`);
const [header, payload, signature] = accessToken.split(".")
const parse = (str) => JSON.parse(Buffer.from(str, "base64url").toString("utf-8"))
console.log(`[Header]\n${JSON.stringify(parse(header), null, 2)}\n`)
console.log(`[Payload]\n${JSON.stringify(parse(payload), null, 2)}\n`)
console.log(`[Signature]\n${signature}\n`)
};
main();
const MaxKeyLen = 19;
const Space = "".padStart(MaxKeyLen + 2, " ");
const getLogVal = (val) =>
val.split("\n").map((line, i) => i === 0 ? line : `${Space}${line}`).join("\n")
export const getEnv = (name, error = true) => {
const value = process.env[name]?.trim();
if (value != null) {
console.log(`${name.padEnd(MaxKeyLen, " ")}: ${getLogVal(value)}`)
return value;
}
if (!error) {
return undefined
}
throw new Error(`Missing required environment variable: ${name}`);
};
{
"name": "issue-m2m-token-auth0",
"private": true,
"type": "module",
"scripts": {
"client-credential": "node ./client-credential.js",
"private-key-jwt": "node ./private-key-jwt.js"
},
"author": "mryhryki",
"license": "MIT",
"dependencies": {
"jose": "^5.2.4"
}
}
import {SignJWT} from 'jose';
import crypto from "node:crypto";
import {getEnv} from "./common.js";
const main = async () => {
const auth0Domain = getEnv("AUTH0_DOMAIN");
const auth0ClientId = getEnv("AUTH0_CLIENT_ID");
const auth0Audience = getEnv("AUTH0_AUDIENCE");
const publicKeyId = getEnv("PUBLIC_KEY_ID");
const privateKeyPEM = getEnv("PRIVATE_KEY_PEM");
const privateKey = crypto.createPrivateKey(privateKeyPEM);
console.log("")
const jwt = await new SignJWT({})
.setProtectedHeader({alg: 'RS256', kid: publicKeyId})
.setIssuedAt()
.setIssuer(auth0ClientId)
.setSubject(auth0ClientId)
.setAudience(`https://${auth0Domain}/`)
.setExpirationTime('1m')
.setJti(crypto.webcrypto.randomUUID())
.sign(privateKey);
console.log(`[JWT to Issue Access Token]\n${jwt}\n`)
const requestBody = new URLSearchParams({
audience: auth0Audience,
client_assertion: jwt,
client_assertion_type: "urn:ietf:params:oauth:client-assertion-type:jwt-bearer",
grant_type: 'client_credentials',
})
const response = await fetch(`https://${auth0Domain}/oauth/token`, {
method: "POST",
headers: {
"Content-Type": "application/x-www-form-urlencoded",
},
body: requestBody.toString(),
});
console.log(`[Response Status]\n${response.status}\n`);
const body = await response.text();
console.log(`[Response Body]\n${body}\n`);
const {access_token: accessToken} = JSON.parse(body);
console.log(`[Access Token]\n${accessToken}\n`);
const [header, payload, signature] = accessToken.split(".")
const parse = (str) => JSON.parse(Buffer.from(str, "base64url").toString("utf-8"))
console.log(`[Header]\n${JSON.stringify(parse(header), null, 2)}\n`)
console.log(`[Payload]\n${JSON.stringify(parse(payload), null, 2)}\n`)
console.log(`[Signature]\n${signature}\n`)
}
main();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment