Skip to content

Commit

Permalink
feat: github login (#211)
Browse files Browse the repository at this point in the history
Allows login via github via:

```sh
w3 login --github
```

refs storacha/RFC#43
depends on storacha/w3up#1629
  • Loading branch information
alanshaw authored Feb 25, 2025
1 parent 1a1b598 commit 64838b1
Show file tree
Hide file tree
Showing 5 changed files with 3,743 additions and 2,026 deletions.
89 changes: 87 additions & 2 deletions account.js
Original file line number Diff line number Diff line change
@@ -1,17 +1,48 @@
import open from 'open'
import { confirm } from '@inquirer/prompts'
import * as Account from '@web3-storage/w3up-client/account'
import * as Result from '@web3-storage/w3up-client/result'
import * as DidMailto from '@web3-storage/did-mailto'
import { authorize } from '@web3-storage/capabilities/access'
import { base64url } from 'multiformats/bases/base64'
import { getClient } from './lib.js'
import ora from 'ora'

/**
* @typedef {Awaited<ReturnType<Account.login>>['ok']&{}} View
*/

export const OAuthProviderGitHub = 'github'
const OAuthProviders = /** @type {const} */ ([OAuthProviderGitHub])

/** @type {Record<import('@web3-storage/w3up-client/types').DID, string>} */
const GitHubOauthClientIDs = {
'did:web:web3.storage': 'Ov23li0xr95ocCkZiwaD',
'did:web:staging.web3.storage': 'Ov23liDKQB1ePrcGy5HI',
}

/** @param {import('@web3-storage/w3up-client/types').DID} serviceID */
const getGithubOAuthClientID = serviceID => {
const id = process.env.GITHUB_OAUTH_CLIENT_ID || GitHubOauthClientIDs[serviceID]
if (!id) throw new Error(`missing OAuth client ID for: ${serviceID}`)
return id
}

/**
* @param {DidMailto.EmailAddress} email
* @param {DidMailto.EmailAddress} [email]
* @param {object} [options]
* @param {boolean} [options.github]
*/
export const login = async (email) => loginWithClient(email, await getClient())
export const login = async (email, options) => {
if (email) {
await loginWithClient(email, await getClient())
} else if (options?.github) {
await oauthLoginWithClient(OAuthProviderGitHub, await getClient())
} else {
console.error('Error: please provide email address or specify flag for alternate login method')
process.exit(1)
}
}

/**
* @param {DidMailto.EmailAddress} email
Expand Down Expand Up @@ -43,6 +74,60 @@ export const loginWithClient = async (email, client) => {
}
}

/**
* @param {(typeof OAuthProviders)[number]} provider OAuth provider
* @param {import('@web3-storage/w3up-client').Client} client
*/
export const oauthLoginWithClient = async (provider, client) => {
if (provider != OAuthProviderGitHub) {
console.error(`Error: unknown OAuth provider: ${provider}`)
process.exit(1)
}

/** @type {import('ora').Ora|undefined} */
let spinner

try {
// create access/authorize request
const request = await authorize.delegate({
audience: client.agent.connection.id,
issuer: client.agent.issuer,
// agent that should be granted access
with: client.agent.did(),
// capabilities requested (account access)
nb: { att: [{ can: '*' }] }
})
const archive = await request.archive()
if (archive.error) {
throw new Error('archiving access authorize delegation', { cause: archive.error })
}

const clientID = getGithubOAuthClientID(client.agent.connection.id.did())
const state = base64url.encode(archive.ok)
const loginURL = `https://github.com/#/oauth/authorize?scope=read:user,user:email&client_id=${clientID}&state=${state}`

if (await confirm({ message: 'Open the GitHub login URL in your default browser?' })) {
spinner = ora('Waiting for GitHub authorization to be completed in browser...').start()
await open(loginURL)
} else {
spinner = ora(`Click the link to authenticate with GitHub: ${loginURL}`).start()
}

const expiration = Math.floor(Date.now() / 1000) + (60 * 15)
const account = Result.unwrap(await Account.externalLogin(client, { request: request.cid, expiration }))

Result.unwrap(await account.save())

if (spinner) spinner.stop()
console.log(`⁂ Agent was authorized by ${account.did()}`)
return account
} catch (err) {
if (spinner) spinner.stop()
console.error(err)
process.exit(1)
}
}

/**
*
*/
Expand Down
3 changes: 2 additions & 1 deletion bin.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,11 +54,12 @@ cli
.example('up path/to/files')

cli
.command('login <email>')
.command('login [email]')
.example('login user@example.com')
.describe(
'Authenticate this agent with your email address to gain access to all capabilities that have been delegated to it.'
)
.option('--github', 'Use GitHub to authenticate. GitHub developer accounts automatically gain access to a trial plan.', false)
.action(Account.login)

cli
Expand Down
Loading

0 comments on commit 64838b1

Please # to comment.