Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 | 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x | import { bytesToHex, getGlobalObject } from 'micro-stacks/common';
import { getPublicKey, getRandomBytes, TokenSigner } from 'micro-stacks/crypto';
import { decodeAuthResponse } from './auth/decode-auth-response';
import { getStacksProvider } from './common/get-stacks-provider';
import { PersistedDataKeys } from './common/constants';
import { defaultStorageAdapter } from './common/utils';
import type { StacksProvider } from './common/provider';
import type { Json } from 'micro-stacks/crypto';
import type { AuthRequestPayload, AuthOptions, AuthScope } from './auth/types';
export async function authenticate(
authOptions: AuthOptions,
storageAdapter = defaultStorageAdapter,
serialize = JSON.stringify
) {
Iif (!authOptions.appDetails) {
throw Error(
'[micro-stacks] authenticate error: `authOptions.appDetails` are required for authentication'
);
}
try {
const transitPrivateKey = bytesToHex(getRandomBytes());
const authResponseToken = await handleAuthResponse(authOptions, transitPrivateKey);
const sessionState = await decodeAuthResponse(authResponseToken, transitPrivateKey);
authOptions?.onFinish?.(sessionState);
storageAdapter.setItem(PersistedDataKeys.SessionStorageKey, serialize(sessionState));
return sessionState;
} catch (e) {
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
authOptions?.onCancel?.((e as any).message);
}
}
export function generateAuthRequestPayload(authOptions: AuthOptions, transitPublicKey: string) {
Iif (!authOptions.appDetails) {
throw Error(
'[micro-stacks] authenticate error: `authOptions.appDetails` are required for authentication'
);
}
const _scopes = authOptions.scopes || [];
const origin = getGlobalObject('location', { returnEmptyObject: true })!.origin;
const payload: AuthRequestPayload = {
scopes: [...new Set(['store_write', ..._scopes])] as AuthScope[],
redirect_uri: origin,
public_keys: [transitPublicKey],
domain_name: origin,
appDetails: authOptions.appDetails,
};
return payload;
}
export async function signAuthRequest(payload: unknown, transitPrivateKey: string) {
const signer = new TokenSigner('ES256k', transitPrivateKey);
return signer.sign(payload as unknown as Json);
}
export async function generateSignedAuthRequest(
authOptions: AuthOptions,
transitPrivateKey: string
) {
const transitPublicKey = bytesToHex(getPublicKey(transitPrivateKey));
const payload = generateAuthRequestPayload(authOptions, transitPublicKey);
return signAuthRequest(payload, transitPrivateKey);
}
export async function handleAuthResponse(authOptions: AuthOptions, transitPrivateKey: string) {
const Provider: StacksProvider | undefined = getStacksProvider();
Iif (!Provider)
throw Error(
'This function can only be called on the client, and with the presence of StacksProvider'
);
const authRequest = await generateSignedAuthRequest(authOptions, transitPrivateKey);
return Provider!.authenticationRequest(authRequest);
}
declare global {
interface Window {
StacksProvider?: StacksProvider;
}
}
|