UNPKG

@stevesouth/expo-auth-session

Version:

Expo module for browser-based authentication

125 lines (107 loc) 4.6 kB
import Constants, { ExecutionEnvironment } from 'expo-constants'; import * as Linking from 'expo-linking'; import { CreateURLOptions } from 'expo-linking'; import { resolveScheme } from 'expo-linking/build/Schemes'; import { Platform } from 'expo-modules-core'; import qs, { ParsedQs } from 'qs'; export class SessionUrlProvider { private static readonly BASE_URL = `https://auth.expo.io`; private static readonly SESSION_PATH = 'expo-auth-session'; getDefaultReturnUrl(urlPath?: string, options?: Omit<CreateURLOptions, 'queryParams'>): string { const queryParams = SessionUrlProvider.getHostAddressQueryParams(); let path = SessionUrlProvider.SESSION_PATH; if (urlPath) { path = [path, SessionUrlProvider.removeLeadingSlash(urlPath)].filter(Boolean).join('/'); } return Linking.createURL(path, { // The redirect URL doesn't matter for the proxy as long as it's valid, so silence warnings if needed. scheme: options?.scheme ?? resolveScheme({ isSilent: true }), queryParams, isTripleSlashed: options?.isTripleSlashed, }); } getStartUrl(authUrl: string, returnUrl: string): string { if (Platform.OS === 'web' && !Platform.isDOMAvailable) { // Return nothing in SSR envs return ''; } const queryString = qs.stringify({ authUrl, returnUrl, }); return `${this.getRedirectUrl()}/start?${queryString}`; } getRedirectUrl(urlPath?: string): string { if (Platform.OS === 'web') { if (Platform.isDOMAvailable) { return [window.location.origin, urlPath].filter(Boolean).join('/'); } else { // Return nothing in SSR envs return ''; } } const legacyExpoProjectId = Constants.manifest?.originalFullName || Constants.manifest2?.extra?.expoClient?.originalFullName || Constants.manifest?.id; if (!legacyExpoProjectId) { let nextSteps = ''; if (__DEV__) { if (Constants.executionEnvironment === ExecutionEnvironment.Bare) { nextSteps = ' Please ensure you have the latest version of expo-constants installed and rebuild your native app. You can verify that originalFullName is defined by running `expo config --type public` and inspecting the output.'; } else if (Constants.executionEnvironment === ExecutionEnvironment.StoreClient) { nextSteps = ' Please report this as a bug with the contents of `expo config --type public`.'; } } throw new Error( 'Cannot use AuthSession proxy because the project ID is not defined.' + nextSteps ); } const redirectUrl = `${SessionUrlProvider.BASE_URL}/${legacyExpoProjectId}`; if (__DEV__) { SessionUrlProvider.warnIfAnonymous(legacyExpoProjectId, redirectUrl); // TODO: Verify with the dev server that the manifest is up to date. } return redirectUrl; } private static getHostAddressQueryParams(): ParsedQs | undefined { let hostUri: string | undefined = Constants.manifest?.hostUri ?? Constants.manifest2?.extra?.expoClient?.hostUri; if ( !hostUri && (ExecutionEnvironment.StoreClient === Constants.executionEnvironment || resolveScheme({})) ) { if (!Constants.linkingUri) { hostUri = ''; } else { // we're probably not using up-to-date xdl, so just fake it for now // we have to remove the /--/ on the end since this will be inserted again later hostUri = SessionUrlProvider.removeScheme(Constants.linkingUri).replace(/\/--(\/.*)?$/, ''); } } if (!hostUri) { return undefined; } const uriParts = hostUri?.split('?'); try { return qs.parse(uriParts?.[1]); } catch {} return undefined; } private static warnIfAnonymous(id, url): void { if (id.startsWith('@anonymous/')) { console.warn( `You are not currently signed in to Expo on your development machine. As a result, the redirect URL for AuthSession will be "${url}". If you are using an OAuth provider that requires adding redirect URLs to an allow list, we recommend that you do not add this URL -- instead, you should sign in to Expo to acquire a unique redirect URL. Additionally, if you do decide to publish this app using Expo, you will need to register an account to do it.` ); } } private static removeScheme(url: string) { return url.replace(/^[a-zA-Z0-9+.-]+:\/\//, ''); } private static removeLeadingSlash(url: string) { return url.replace(/^\//, ''); } } export default new SessionUrlProvider();