commit
375c69d27c
@ -1,4 +1,4 @@ |
|||||||
{ |
{ |
||||||
"$schema": "node_modules/lerna/schemas/lerna-schema.json", |
"$schema": "node_modules/lerna/schemas/lerna-schema.json", |
||||||
"version": "0.0.1-alpha.27" |
"version": "0.0.1-alpha.28" |
||||||
} |
} |
||||||
|
File diff suppressed because it is too large
Load Diff
@ -1,8 +1,9 @@ |
|||||||
[ |
[ |
||||||
{ |
{ |
||||||
"podName": "example", |
|
||||||
"email": "hello@example.com", |
"email": "hello@example.com", |
||||||
"password": "abc123", |
"password": "abc123", |
||||||
"template": "./template" |
"pods": [ |
||||||
|
{ "name": "example" } |
||||||
|
] |
||||||
} |
} |
||||||
] |
] |
@ -0,0 +1 @@ |
|||||||
|
module.exports = { presets: ["@babel/preset-env"] }; |
@ -0,0 +1,112 @@ |
|||||||
|
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(); |
||||||
|
|
||||||
|
// 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(); |
||||||
|
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(); |
||||||
|
|
||||||
|
// 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(); |
||||||
|
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.
|
||||||
|
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"; |
||||||
|
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", |
||||||
|
}); |
||||||
|
|
||||||
|
// 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.json(); |
||||||
|
return { accessToken: response2.access_token, dpopKey }; |
||||||
|
} catch (err) { |
||||||
|
console.error(err); |
||||||
|
throw err; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
export async function generateAuthFetch() { |
||||||
|
const authorization = await getAuthorization(); |
||||||
|
const { id, secret } = await getSecret(authorization); |
||||||
|
const { accessToken, dpopKey } = await getAccessToken(id, secret); |
||||||
|
return await buildAuthenticatedFetch(accessToken, { dpopKey }); |
||||||
|
} |
@ -0,0 +1,43 @@ |
|||||||
|
{ |
||||||
|
"@context": [ |
||||||
|
"https://linkedsoftwaredependencies.org/bundles/npm/@solid/community-server/^7.0.0/components/context.jsonld" |
||||||
|
], |
||||||
|
"import": [ |
||||||
|
"css:config/app/init/static-root.json", |
||||||
|
"css:config/app/main/default.json", |
||||||
|
"css:config/app/variables/default.json", |
||||||
|
"css:config/http/handler/default.json", |
||||||
|
"css:config/http/middleware/default.json", |
||||||
|
"css:config/http/notifications/all.json", |
||||||
|
"css:config/http/server-factory/http.json", |
||||||
|
"css:config/http/static/default.json", |
||||||
|
"css:config/identity/access/public.json", |
||||||
|
"css:config/identity/email/default.json", |
||||||
|
"css:config/identity/handler/default.json", |
||||||
|
"css:config/identity/oidc/default.json", |
||||||
|
"css:config/identity/ownership/token.json", |
||||||
|
"css:config/identity/pod/static.json", |
||||||
|
"css:config/ldp/authentication/dpop-bearer.json", |
||||||
|
"css:config/ldp/authorization/webacl.json", |
||||||
|
"css:config/ldp/handler/default.json", |
||||||
|
"css:config/ldp/metadata-parser/default.json", |
||||||
|
"css:config/ldp/metadata-writer/default.json", |
||||||
|
"css:config/ldp/modes/default.json", |
||||||
|
"css:config/storage/backend/memory.json", |
||||||
|
"css:config/storage/key-value/resource-store.json", |
||||||
|
"css:config/storage/location/pod.json", |
||||||
|
"css:config/storage/middleware/default.json", |
||||||
|
"css:config/util/auxiliary/acl.json", |
||||||
|
"css:config/util/identifiers/suffix.json", |
||||||
|
"css:config/util/index/default.json", |
||||||
|
"css:config/util/logging/winston.json", |
||||||
|
"css:config/util/representation-conversion/default.json", |
||||||
|
"css:config/util/resource-locker/memory.json", |
||||||
|
"css:config/util/variables/default.json" |
||||||
|
], |
||||||
|
"@graph": [ |
||||||
|
{ |
||||||
|
"comment": "A Solid server that stores its resources on disk and uses WAC for authorization." |
||||||
|
} |
||||||
|
] |
||||||
|
} |
@ -1,7 +1,9 @@ |
|||||||
[ |
[ |
||||||
{ |
{ |
||||||
"podName": "example", |
|
||||||
"email": "hello@example.com", |
"email": "hello@example.com", |
||||||
"password": "abc123" |
"password": "abc123", |
||||||
|
"pods": [ |
||||||
|
{ "name": "example" } |
||||||
|
] |
||||||
} |
} |
||||||
] |
] |
Loading…
Reference in new issue