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
4 changes: 2 additions & 2 deletions example/ios/Podfile.lock
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
PODS:
- A0Auth0 (5.1.0):
- A0Auth0 (5.2.1):
- Auth0 (= 2.14)
- boost
- DoubleConversion
Expand Down Expand Up @@ -2778,7 +2778,7 @@ EXTERNAL SOURCES:
:path: "../node_modules/react-native/ReactCommon/yoga"

SPEC CHECKSUMS:
A0Auth0: 022a85f2093860dcbf9e5337946f6cda5780de4d
A0Auth0: 9253099fae9372f663f89abbf5d02a6b36faf45c
Auth0: 022dda235af8a664a4faf9e7b60b063b5bc08373
boost: 7e761d76ca2ce687f7cc98e698152abd03a18f90
DoubleConversion: cb417026b2400c8f53ae97020b2be961b59470cb
Expand Down
6 changes: 5 additions & 1 deletion example/src/screens/class-based/ClassLogin.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import Button from '../../components/Button';
import Header from '../../components/Header';
import Result from '../../components/Result';
import type { ClassDemoStackParamList } from '../../navigation/ClassDemoNavigator';
import config from '../../auth0-configuration';

type NavigationProp = StackNavigationProp<
ClassDemoStackParamList,
Expand All @@ -24,7 +25,10 @@ const ClassLoginScreen = () => {
setLoading(true);
setError(null);
try {
const credentials = await auth0.webAuth.authorize();
const credentials = await auth0.webAuth.authorize({
scope: 'openid profile email offline_access',
audience: `https://${config.domain}/api/v2/`,
});
// On success, we save the credentials and navigate to the profile screen.
await auth0.credentialsManager.saveCredentials(credentials);
navigation.replace('ClassProfile', { credentials });
Expand Down
69 changes: 66 additions & 3 deletions example/src/screens/class-based/ClassProfile.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
StyleSheet,
Text,
Alert,
Linking,
} from 'react-native';
import { RouteProp, NavigationProp } from '@react-navigation/native';
import { jwtDecode } from 'jwt-decode';
Expand All @@ -16,7 +17,6 @@ import UserInfo from '../../components/UserInfo';
import { User, Credentials, ApiCredentials } from 'react-native-auth0';
import type { ClassDemoStackParamList } from '../../navigation/ClassDemoNavigator';
import LabeledInput from '../../components/LabeledInput';
import config from '../../auth0-configuration';
import Result from '../../components/Result';

type ProfileRouteProp = RouteProp<ClassDemoStackParamList, 'ClassProfile'>;
Expand All @@ -31,6 +31,7 @@ interface State {
result: Credentials | ApiCredentials | object | boolean | null;
error: Error | null;
audience: string;
webAppUrl: string;
}

class ClassProfileScreen extends Component<Props, State> {
Expand All @@ -41,7 +42,8 @@ class ClassProfileScreen extends Component<Props, State> {
user,
result: null,
error: null,
audience: config.audience,
audience: '',
webAppUrl: 'https://your-web-app.com/login',
};
}

Expand Down Expand Up @@ -74,7 +76,7 @@ class ClassProfileScreen extends Component<Props, State> {
};

render() {
const { user, result, error, audience } = this.state;
const { user, result, error, audience, webAppUrl } = this.state;
const { accessToken } = this.props.route.params.credentials;

return (
Expand Down Expand Up @@ -143,6 +145,65 @@ class ClassProfileScreen extends Component<Props, State> {
/>
</Section>

<Section title="Native to Web SSO (Early Access)">
<Text style={styles.description}>
Exchange your refresh token for a Session Transfer Token to enable
seamless SSO to your web application.
</Text>
<LabeledInput
label="Web App URL"
value={webAppUrl}
onChangeText={(text) => this.setState({ webAppUrl: text })}
autoCapitalize="none"
placeholder="https://your-web-app.com/login"
/>
<Button
onPress={() =>
this.runTest(
() => auth0.credentialsManager.getSSOCredentials(),
'Get SSO Credentials'
)
}
title="credentialsManager.getSSOCredentials()"
/>
<Button
onPress={async () => {
try {
this.setState({ error: null });
const ssoCredentials =
await auth0.credentialsManager.getSSOCredentials();
this.setState({ result: ssoCredentials });

// Open web app with session transfer token
const url = `${webAppUrl}?session_transfer_token=${ssoCredentials.sessionTransferToken}`;

Alert.alert(
'Open Web App',
`Open ${webAppUrl} with session transfer token?`,
[
{ text: 'Cancel', style: 'cancel' },
{
text: 'Open',
onPress: async () => {
const supported = await Linking.canOpenURL(url);
if (supported) {
await Linking.openURL(url);
} else {
Alert.alert('Error', `Cannot open URL: ${url}`);
}
},
},
]
);
} catch (e) {
this.setState({ error: e as Error });
}
}}
title="Get SSO Credentials & Open Web App"
style={styles.primaryButton}
/>
</Section>

<Section title="Navigation & Logout">
<Button
onPress={() =>
Expand Down Expand Up @@ -188,8 +249,10 @@ const styles = StyleSheet.create({
},
sectionTitle: { fontSize: 18, fontWeight: 'bold', marginBottom: 12 },
buttonGroup: { gap: 10 },
description: { fontSize: 14, color: '#757575', marginBottom: 10 },
destructiveButton: { backgroundColor: '#424242' },
secondaryButton: { backgroundColor: '#FF9800' },
primaryButton: { backgroundColor: '#4CAF50' },
});

export default ClassProfileScreen;
70 changes: 67 additions & 3 deletions example/src/screens/hooks/CredentialsScreen.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,18 @@
import React, { useState } from 'react';
import { SafeAreaView, ScrollView, StyleSheet, View, Text } from 'react-native';
import {
SafeAreaView,
ScrollView,
StyleSheet,
View,
Text,
Linking,
Alert,
} from 'react-native';
import { useAuth0, Credentials, ApiCredentials } from 'react-native-auth0';
import Button from '../../components/Button';
import Header from '../../components/Header';
import Result from '../../components/Result';
import LabeledInput from '../../components/LabeledInput';
import config from '../../auth0-configuration';

const CredentialsScreen = () => {
const {
Expand All @@ -15,14 +22,16 @@ const CredentialsScreen = () => {
getApiCredentials,
clearApiCredentials,
revokeRefreshToken,
getSSOCredentials,
} = useAuth0();

const [result, setResult] = useState<
Credentials | ApiCredentials | object | boolean | null
>(null);
const [error, setError] = useState<Error | null>(null);
const [audience, setAudience] = useState(config.audience);
const [audience, setAudience] = useState('');
const [scope, setScope] = useState('openid profile email');
const [webAppUrl, setWebAppUrl] = useState('https://your-web-app.com/login');

const runTest = async (testFn: () => Promise<any>, title: string) => {
setError(null);
Expand Down Expand Up @@ -117,6 +126,59 @@ const CredentialsScreen = () => {
style={styles.secondaryButton}
/>
</Section>

<Section title="Native to Web SSO (Early Access)">
<Text style={styles.description}>
Exchange your refresh token for a Session Transfer Token to enable
seamless SSO to your web application.
</Text>
<LabeledInput
label="Web App URL"
value={webAppUrl}
onChangeText={setWebAppUrl}
autoCapitalize="none"
placeholder="https://your-web-app.com/login"
/>
<Button
onPress={() => runTest(getSSOCredentials, 'Get SSO Credentials')}
title="getSSOCredentials()"
/>
<Button
onPress={async () => {
try {
setError(null);
const ssoCredentials = await getSSOCredentials();
setResult(ssoCredentials);

// Open web app with session transfer token
const url = `${webAppUrl}?session_transfer_token=${ssoCredentials.sessionTransferToken}`;

Alert.alert(
'Open Web App',
`Open ${webAppUrl} with session transfer token?`,
[
{ text: 'Cancel', style: 'cancel' },
{
text: 'Open',
onPress: async () => {
const supported = await Linking.canOpenURL(url);
if (supported) {
await Linking.openURL(url);
} else {
Alert.alert('Error', `Cannot open URL: ${url}`);
}
},
},
]
);
} catch (e) {
setError(e as Error);
}
}}
title="Get SSO Credentials & Open Web App"
style={styles.primaryButton}
/>
</Section>
</ScrollView>
</SafeAreaView>
);
Expand Down Expand Up @@ -147,8 +209,10 @@ const styles = StyleSheet.create({
},
sectionTitle: { fontSize: 18, fontWeight: 'bold', marginBottom: 12 },
buttonGroup: { gap: 10 },
description: { fontSize: 14, color: '#757575', marginBottom: 10 },
destructiveButton: { backgroundColor: '#424242' },
secondaryButton: { backgroundColor: '#FF9800' },
primaryButton: { backgroundColor: '#4CAF50' },
});

export default CredentialsScreen;
6 changes: 5 additions & 1 deletion example/src/screens/hooks/Home.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import Button from '../../components/Button';
import Header from '../../components/Header';
import LabeledInput from '../../components/LabeledInput';
import Result from '../../components/Result';
import config from '../../auth0-configuration';

const HomeScreen = () => {
const {
Expand All @@ -30,7 +31,10 @@ const HomeScreen = () => {

const onLogin = async () => {
try {
await authorize();
await authorize({
scope: 'openid profile email offline_access',
audience: `https://${config.domain}/api/v2/`,
});
} catch (e) {
console.log('Login error: ', e);
}
Expand Down
11 changes: 5 additions & 6 deletions ios/NativeBridge.swift
Original file line number Diff line number Diff line change
Expand Up @@ -244,19 +244,18 @@ public class NativeBridge: NSObject {
}

@objc public func getSSOCredentials(parameters: [String: Any], headers: [String: Any], resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
credentialsManager.ssoCredentials(parameters: parameters, headers: headers) { result in
let stringHeaders = headers.compactMapValues { $0 as? String }
credentialsManager.ssoCredentials(parameters: parameters, headers: stringHeaders) { result in
switch result {
case .success(let ssoCredentials):
var response: [String: Any] = [
"sessionTransferToken": ssoCredentials.sessionTransferToken,
"tokenType": ssoCredentials.tokenType,
"expiresIn": ssoCredentials.expiresIn
"tokenType": ssoCredentials.issuedTokenType,
"expiresIn": ssoCredentials.expiresIn,
"idToken": ssoCredentials.idToken
]

// Add optional fields if present
if let idToken = ssoCredentials.idToken {
response["idToken"] = idToken
}
if let refreshToken = ssoCredentials.refreshToken {
response["refreshToken"] = refreshToken
}
Expand Down
Loading