You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
134 lines
4.8 KiB
134 lines
4.8 KiB
import type { KeyPair } from "@inrupt/solid-client-authn-core";
|
|
import {
|
|
buildAuthenticatedFetch,
|
|
createDpopHeader,
|
|
generateDpopKeyPair,
|
|
} from "@inrupt/solid-client-authn-core";
|
|
import fetch from "cross-fetch";
|
|
|
|
const config = {
|
|
podName: process.env.USER_NAME || "example",
|
|
email: process.env.EMAIL || "hello@example.com",
|
|
password: process.env.PASSWORD || "abc123",
|
|
};
|
|
|
|
async function getAuthorization(): Promise<string> {
|
|
// First we request the account API controls to find out where we can log in
|
|
const indexResponse = await fetch("http://localhost:3001/.account/");
|
|
const { controls } = await indexResponse.json();
|
|
|
|
console.log("First controls", controls);
|
|
|
|
// And then we log in to the account API
|
|
const response = await fetch(controls.password.login, {
|
|
method: "POST",
|
|
headers: { "content-type": "application/json" },
|
|
body: JSON.stringify({
|
|
email: config.email,
|
|
password: config.password,
|
|
}),
|
|
});
|
|
// This authorization value will be used to authenticate in the next step
|
|
const result = await response.json();
|
|
console.log(result);
|
|
return result.authorization;
|
|
}
|
|
|
|
async function getSecret(
|
|
authorization: string,
|
|
): Promise<{ id: string; secret: string; resource: string }> {
|
|
// Now that we are logged in, we need to request the updated controls from the server.
|
|
// These will now have more values than in the previous example.
|
|
const indexResponse = await fetch("http://localhost:3001/.account/", {
|
|
headers: { authorization: `CSS-Account-Token ${authorization}` },
|
|
});
|
|
const { controls } = await indexResponse.json();
|
|
|
|
console.log("controls", controls);
|
|
console.log("authorization", authorization);
|
|
|
|
// Here we request the server to generate a token on our account
|
|
const response = await fetch(controls.account.clientCredentials, {
|
|
method: "POST",
|
|
headers: {
|
|
authorization: `CSS-Account-Token ${authorization}`,
|
|
"content-type": "application/json",
|
|
},
|
|
// The name field will be used when generating the ID of your token.
|
|
// The WebID field determines which WebID you will identify as when using the token.
|
|
// Only WebIDs linked to your account can be used.
|
|
body: JSON.stringify({
|
|
name: "my-token",
|
|
webId: `http://localhost:3001/${config.podName}/profile/card#me`,
|
|
}),
|
|
});
|
|
|
|
// These are the identifier and secret of your token.
|
|
// Store the secret somewhere safe as there is no way to request it again from the server!
|
|
// The `resource` value can be used to delete the token at a later point in time.
|
|
const response2 = await response.json();
|
|
console.log("response2", response2);
|
|
return response2;
|
|
}
|
|
|
|
async function getAccessToken(
|
|
id: string,
|
|
secret: string,
|
|
): Promise<{ accessToken: string; dpopKey: KeyPair }> {
|
|
try {
|
|
// A key pair is needed for encryption.
|
|
// This function from `solid-client-authn` generates such a pair for you.
|
|
console.log("a");
|
|
const dpopKey = await generateDpopKeyPair();
|
|
|
|
// These are the ID and secret generated in the previous step.
|
|
// Both the ID and the secret need to be form-encoded.
|
|
const authString = `${encodeURIComponent(id)}:${encodeURIComponent(
|
|
secret,
|
|
)}`;
|
|
// This URL can be found by looking at the "token_endpoint" field at
|
|
// http://localhost:3001/.well-known/openid-configuration
|
|
// if your server is hosted at http://localhost:3000/.
|
|
const tokenUrl = "http://localhost:3001/.oidc/token";
|
|
console.log("b");
|
|
const response = await fetch(tokenUrl, {
|
|
method: "POST",
|
|
headers: {
|
|
// The header needs to be in base64 encoding.
|
|
authorization: `Basic ${Buffer.from(authString).toString("base64")}`,
|
|
"content-type": "application/x-www-form-urlencoded",
|
|
dpop: await createDpopHeader(tokenUrl, "POST", dpopKey),
|
|
},
|
|
body: "grant_type=client_credentials&scope=webid",
|
|
});
|
|
console.log("c");
|
|
|
|
// console.log(process.env.JEST_WORKER_ID ?? process.env.NODE_ENV);
|
|
// console.log(process.env.JEST_WORKER_ID);
|
|
// console.log(process.env.NODE_ENV);
|
|
|
|
console.log("d");
|
|
|
|
// This is the Access token that will be used to do an authenticated request to the server.
|
|
// The JSON also contains an "expires_in" field in seconds,
|
|
// which you can use to know when you need request a new Access token.
|
|
const response2 = await response.text();
|
|
console.log("response2 getAccessToken", response2);
|
|
throw new Error();
|
|
// return { accessToken: response2.accessToken, dpopKey };
|
|
} catch (err) {
|
|
console.error(err);
|
|
throw err;
|
|
}
|
|
}
|
|
|
|
export async function generateAuthFetch() {
|
|
console.log(1);
|
|
const authorization = await getAuthorization();
|
|
console.log(2);
|
|
const { id, secret } = await getSecret(authorization);
|
|
console.log(3);
|
|
const { accessToken, dpopKey } = await getAccessToken(id, secret);
|
|
console.log(4);
|
|
return await buildAuthenticatedFetch(accessToken, { dpopKey });
|
|
}
|
|
|