${client} is asking to sign in to your account.
` + `The code it is showing you should be:
` + `${code.slice(0, 4)}-${code.slice(4)}
If those do not match, or you did not start this on a device of your own, ` + `choose Deny. Nobody can sign in as you unless you approve here.
` + `` ); } async function getAuthorization(ctx: Context) { const match = (await auth.get(ctx, 'authorization')) || ctx.get('authorization'); if (!match) throw new UnknownStateError(); return match as AuthorizationState; } async function encrypt(value: any) { return await new CompactEncrypt(new TextEncoder().encode(JSON.stringify(value))) .setProtectedHeader({ alg: 'RSA-OAEP-512', enc: 'A256GCM' }) .encrypt(await encryptionKey().then((k) => k.public)); } async function resolveSubject(type: string, properties: any) { const jsonString = JSON.stringify(properties); const encoder = new TextEncoder(); const data = encoder.encode(jsonString); const hashBuffer = await crypto.subtle.digest('SHA-1', data); const hashArray = Array.from(new Uint8Array(hashBuffer)); const hashHex = hashArray.map((b) => b.toString(16).padStart(2, '0')).join(''); return `${type}:${hashHex.slice(0, 16)}`; } async function generateTokens( ctx: Context, value: { type: string; properties: any; subject: string; clientID: string; ttl: { access: number; refresh: number; }; timeUsed?: number; nextToken?: string; }, opts?: { generateRefreshToken?: boolean; } ) { const refreshToken = value.nextToken ?? crypto.randomUUID(); if (opts?.generateRefreshToken ?? true) { /** * Generate and store the next refresh token after the one we are currently returning. * Reserving these in advance avoids concurrency issues with multiple refreshes. * Similar treatment should be given to any other values that may have race conditions, * for example if a jti claim was added to the access token. */ const refreshValue: RefreshRecord = { ...value, nextToken: crypto.randomUUID() }; delete refreshValue.timeUsed; await refreshStore.create( value.subject, await hashRefreshToken(refreshToken), refreshValue, value.ttl.refresh ); } const accessTimeUsed = Math.floor((value.timeUsed ?? Date.now()) / 1000); return { access: await new SignJWT({ mode: 'access', type: value.type, properties: value.properties, aud: value.clientID, iss: issuer(ctx), sub: value.subject }) .setExpirationTime(Math.floor(accessTimeUsed + value.ttl.access)) .setProtectedHeader( await signingKey().then((k) => ({ alg: k.alg, kid: k.id, typ: 'JWT' })) ) .sign(await signingKey().then((item) => item.private)), expiresIn: Math.floor(accessTimeUsed + value.ttl.access - Date.now() / 1000), refresh: [value.subject, refreshToken].join(':') }; } async function decrypt(value: string) { return JSON.parse( new TextDecoder().decode( await compactDecrypt(value, await encryptionKey().then((v) => v.private)).then( (value) => value.plaintext ) ) ); } function issuer(ctx: Context) { return new URL(getRelativeUrl(ctx, '/')).origin; } const app = new Hono<{ Variables: { authorization: AuthorizationState; }; }>().use(logger()); for (const [name, value] of Object.entries(input.providers)) { const route = new Hono