Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions example/backend/server.js
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,37 @@ app.post('/api/challenge-token', async (req, res) => {
}
});

app.post('/api/launch-url', async (req, res) => {
try {
const { userId } = req.body;

if (!userId) {
return res.status(400).json({ error: 'userId is required' });
}

console.log(` Tracking 'launch' for user: ${userId}`);

const trackResponse = await authsignal.track({
userId,
action: 'launch',
});

console.log(` State: ${trackResponse.state}, URL: ${trackResponse.url}`);

res.json({
url: trackResponse.url,
token: trackResponse.token,
state: trackResponse.state,
});
} catch (error) {
console.error(' Error:', error.message);
res.status(500).json({
error: 'Failed to get launch URL',
details: error.message,
});
}
});

app.post('/api/validate', async (req, res) => {
try {
const { token } = req.body;
Expand Down
2 changes: 1 addition & 1 deletion example/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

69 changes: 69 additions & 0 deletions example/src/screens/HomeScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,58 @@ export function HomeScreen() {
}
};

// --- Launch Methods ---

const launchPopup = async () => {
const authsignal = authsignalRef.current;
if (!authsignal) return;

try {
addOutput('Getting launch URL from backend...');
const response = await BackendService.getLaunchUrl(userId);

if (!response?.url) {
addOutput('Failed to get launch URL');
return;
}

addOutput(`Launch URL received (state: ${response.state})`);
addOutput('Opening in popup mode...');

const token = await authsignal.launch(response.url);

if (token) {
addOutput(`Popup completed! Token: ${token.substring(0, 20)}...`);
} else {
addOutput('Popup closed without completing.');
}
} catch (e) {
addOutput(`Error: ${e}`);
}
};

const launchRedirect = async () => {
const authsignal = authsignalRef.current;
if (!authsignal) return;

try {
addOutput('Getting launch URL from backend...');
const response = await BackendService.getLaunchUrl(userId);

if (!response?.url) {
addOutput('Failed to get launch URL');
return;
}

addOutput(`Launch URL received (state: ${response.state})`);
addOutput('Redirecting...');

await authsignal.launch(response.url, { mode: 'redirect' });
} catch (e) {
addOutput(`Error: ${e}`);
}
};

// --- Passkey Methods ---

const registerPasskey = async () => {
Expand Down Expand Up @@ -550,6 +602,23 @@ export function HomeScreen() {
onInitialize={initializeSDK}
/>

{/* Launch */}
<FeatureCard
title="Launch (web only)"
description="Test popup vs redirect mode for the prebuilt MFA page."
>
<ActionButton
title="Launch Popup"
onPress={launchPopup}
disabled={!isInitialized}
/>
<ActionButton
title="Launch Redirect"
onPress={launchRedirect}
disabled={!isInitialized}
/>
</FeatureCard>

{/* Passkeys */}
<FeatureCard
title="Passkeys (web + mobile)"
Expand Down
25 changes: 25 additions & 0 deletions example/src/services/BackendService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,12 @@ export interface ChallengeTokenResponse {
message?: string;
}

export interface LaunchUrlResponse {
url: string;
token: string;
state?: string;
}

export interface ValidationResponse {
isValid: boolean;
state?: string;
Expand Down Expand Up @@ -113,6 +119,25 @@ class BackendServiceImpl {
}
}

async getLaunchUrl(userId: string): Promise<LaunchUrlResponse | null> {
try {
const response = await fetch(`${this.baseUrl}/api/launch-url`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ userId }),
});

if (response.ok) {
return await response.json();
}
console.log(`Failed to get launch URL: ${response.status}`);
return null;
} catch (e) {
console.log(`Backend connection error: ${e}`);
return null;
}
}

async checkHealth(): Promise<boolean> {
try {
const controller = new AbortController();
Expand Down
6 changes: 3 additions & 3 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "react-native-authsignal",
"version": "2.6.0",
"version": "2.6.1",
"description": "The official Authsignal React Native library.",
"main": "lib/commonjs/index",
"module": "lib/module/index",
Expand Down
5 changes: 1 addition & 4 deletions src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -71,10 +71,7 @@ export class Authsignal {
await AuthsignalModule.setToken(token);
}

async launch(
url: string,
_options?: LaunchOptions
): Promise<string | null> {
async launch(url: string, _options?: LaunchOptions): Promise<string | null> {
return await launch(url);
}
}
Expand Down
14 changes: 7 additions & 7 deletions src/index.web.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -64,10 +64,7 @@ export class Authsignal {
client.setToken(token);
}

async launch(
url: string,
options?: LaunchOptions
): Promise<string | null> {
async launch(url: string, options?: LaunchOptions): Promise<string | null> {
return await launch(url, options);
}
}
Expand All @@ -76,16 +73,19 @@ export function launch(
url: string,
options?: LaunchOptions
): Promise<string | null> {
const mode = options?.mode ?? 'popup';

if (_lastClient) {
const client = getOrCreateWebClient({
tenantID: _lastClient.tenantID,
baseURL: _lastClient.baseURL,
enableLogging: _lastClient.enableLogging,
});

return client.launch(url, { mode }).then((result) => {
if (options?.mode === 'redirect') {
client.launch(url, { mode: 'redirect' });
return Promise.resolve(null);
}

return client.launch(url, { mode: 'popup' }).then((result) => {
return result?.token ?? null;
});
}
Expand Down
4 changes: 1 addition & 3 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -131,10 +131,8 @@ export interface DeletePinInput {
username: string;
}

export type LaunchMode = 'popup' | 'redirect';

export interface LaunchOptions {
mode?: LaunchMode;
mode?: 'popup' | 'redirect';
}

export enum KeychainAccess {
Expand Down
Loading