Skip to content
Open
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
24 changes: 18 additions & 6 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ executors:

macos:
macos:
xcode: "16.3"
xcode: 26.4.1
resource_class: m4pro.medium

jobs:
Expand All @@ -34,10 +34,16 @@ jobs:
- gradle-

- run:
name: Run Android Unit and Integration Tests
name: Setup Node and install dependencies
command: |
cd packages/react-native-webcrypto-bridge/android
./gradlew testDebugUnitTest --info
npm i -g yarn@1.22.22
yarn install --frozen-lockfile

- run:
name: Run React Native Platform Android Tests
command: |
cd packages/react-native-platform/android
./gradlew testDebugUnitTest -PnewArchEnabled=true --info

- save_cache:
key: gradle-{{ checksum "packages/react-native-webcrypto-bridge/android/build.gradle" }}
Expand Down Expand Up @@ -93,11 +99,17 @@ jobs:
- gradle-rn-platform-{{ checksum "packages/react-native-platform/android/build.gradle" }}
- gradle-rn-platform-

- run:
name: Setup Node and install dependencies
command: |
npm i -g yarn@1.22.22
yarn install --frozen-lockfile

- run:
name: Run React Native Platform Android Tests
command: |
cd packages/react-native-platform/android
./gradlew testDebugUnitTest --info
./gradlew testDebugUnitTest -PnewArchEnabled=true --info

- save_cache:
key: gradle-rn-platform-{{ checksum "packages/react-native-platform/android/build.gradle" }}
Expand Down Expand Up @@ -147,4 +159,4 @@ workflows:
- test-rn-webcrypto-android
- test-rn-webcrypto-ios
- test-rn-platform-android
- test-rn-platform-ios
# - test-rn-platform-ios
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ docs/api/*
out/
build
dist
.build


# Debug
Expand Down
8 changes: 7 additions & 1 deletion e2e/apps/react-native-oidc/app.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import envModule from '@repo/env';
envModule.setEnvironmentVarsFromTestEnv(__dirname);
const env: any = {};
// List of environment variables made available to the app
['ISSUER', 'NATIVE_CLIENT_ID', 'USE_DPOP'].forEach((key) => {
['ISSUER', 'NATIVE_CLIENT_ID', 'NATIVE_REDIRECT_URI', 'USE_DPOP'].forEach((key) => {
if (!process.env[key]) {
console.warn(`Environment variable ${key} should be set for development. See README.md`);
}
Expand All @@ -26,6 +26,12 @@ export default ({ config }: ConfigContext) => ({
"bundleIdentifier": "com.anonymous.reporeactnativeoidc"
},
scheme: "com.oktapreview.jperreault-test",
autolinking: {
searchPaths: [
"../../node_modules",
"../../packages"
]
},
intentFilters: [
{
action: "VIEW",
Expand Down
39 changes: 39 additions & 0 deletions e2e/apps/react-native-oidc/app/callback.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { useEffect } from 'react';
import { useRouter, useLocalSearchParams } from 'expo-router';
import { ActivityIndicator, StyleSheet } from 'react-native';
import { ThemedView } from '@/components/ThemedView';
import { ThemedText } from '@/components/ThemedText';
import { useAuth } from '@/hooks/useAuth';


export default function CallbackScreen() {
const router = useRouter();
const searchParams = useLocalSearchParams<Record<string, string>>();
const { handleAuthFlowExchange } = useAuth();

useEffect(() => {
const handleExchange = async () => {
const params = { ...searchParams };
await handleAuthFlowExchange(new URLSearchParams(params));
router.replace('/');
}

handleExchange();
}, [router, searchParams, handleAuthFlowExchange]);

return (
<ThemedView style={styles.container}>
<ActivityIndicator size="large" />
<ThemedText>Processing login...</ThemedText>
</ThemedView>
);
}

const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
padding: 20,
},
});
68 changes: 65 additions & 3 deletions e2e/apps/react-native-oidc/auth.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,19 @@
import { fetch as expoFetch, FetchResponse } from 'expo/fetch';
import Constants from 'expo-constants';
import { Platform } from 'react-native';
import { OAuth2Client } from '@okta/auth-foundation/core';
import {
AuthorizationCodeFlow,
SessionLogoutFlow,
AuthTransaction,
Credential,
openAuthSession
} from '@okta/react-native-platform';


export const client = new OAuth2Client({
baseURL: Constants?.expoConfig?.extra?.env.ISSUER,
clientId: Constants?.expoConfig?.extra?.env.NATIVE_CLIENT_ID,
// TODO: skip OIDC to avoid PK import errors
scopes: ['openid', 'email', 'profile', 'offline_access'],
// scopes: ['offline_access'],
dpop: false,
fetchImpl: async (input: string | URL | Request, init?: RequestInit) => {
// const { body, ...rest } = { body: undefined, ...init };
Expand All @@ -24,3 +29,60 @@ export const client = new OAuth2Client({
return response;
}
});

export const flow = new AuthorizationCodeFlow(client, {
redirectUri: Constants?.expoConfig?.extra?.env.NATIVE_REDIRECT_URI
});

export async function handleAuthFlowCallback (params: string | URLSearchParams) {
try {
const { token, context } = await flow.resume(params);
console.log('token', token);
console.log('context', context);
const credential = await Credential.store(token);
return credential.id;
}
catch (err) {
console.log('here 3');
console.log(err, (err as Error)?.stack);
Comment on lines +46 to +47

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FYI some additional debugging logs

throw err;
}
finally {
flow.reset();
}
}

export async function performSignIn () {
try {
console.log('here 1')
const uri = await flow.start();

// @ts-ignore
const transaction = new AuthTransaction(flow.context);
await transaction.save();
console.log('here 2.5 - transaction saved')
const result = await openAuthSession(uri.href, flow.redirectUri);
console.log('result: ', result)

if (result.type === 'success') {
if (['ios', 'macos'].includes(Platform.OS)) {
return await handleAuthFlowCallback(result.url);
}
}

// TODO: handle this
console.log('[WARNING] auth did not complete')
}
catch (err) {
console.log('here 3');
console.log(err, (err as Error)?.stack);
throw err;
}
}

export async function performSignOut () {
const isOIDC = client.configuration.scopes.includes('openid');

// TODO: implement oidc logout
await (await Credential.getDefault())?.revoke();
}
24 changes: 0 additions & 24 deletions e2e/apps/react-native-oidc/components/ExternalLink.tsx

This file was deleted.

64 changes: 9 additions & 55 deletions e2e/apps/react-native-oidc/hooks/useAuth.ts
Original file line number Diff line number Diff line change
@@ -1,65 +1,15 @@
import { useCallback } from 'react';
import { useRouter, type Router } from 'expo-router';
import { Platform } from 'react-native';
import { openAuthSessionAsync } from 'expo-web-browser';
// import { AuthorizationCodeFlow, SessionLogoutFlow, AuthTransaction } from '@okta/oauth2-flows';
// import { Credential } from '@okta/auth-foundation/core';
import {
AuthorizationCodeFlow,
SessionLogoutFlow,
AuthTransaction,
Credential
} from '@okta/react-native-platform';
import { client } from '@/auth';
import { useRouter, type Router, usePathname } from 'expo-router';
import { performSignIn, performSignOut, handleAuthFlowCallback } from '@/auth';


async function performSignIn () {
try {
console.log('here 1')
// Platform-specific redirect URI - iOS uses single slash, Android uses double slash
const redirectUri = Platform.OS === 'ios'
? 'com.oktapreview.jperreault-test:/callback'
: 'com.oktapreview.jperreault-test://callback';

// TODO: move to env
const flow = new AuthorizationCodeFlow(client, {
redirectUri
});

console.log('here 1')
const uri = await flow.start();

// @ts-ignore
const transaction = new AuthTransaction(flow.context);
await transaction.save();
const result = await openAuthSessionAsync(uri.href, redirectUri);
console.log('result: ', result)
// @ts-ignore
const { token, context } = await flow.resume(result.url);
console.log('token', token);
console.log('context', context);
const credential = await Credential.store(token);
return credential.id;
}
catch (err) {
console.log('here 3');
console.log(err, (err as Error)?.stack);
throw err;
}
}

async function performSignOut () {
const isOIDC = client.configuration.scopes.includes('openid');

// TODO: implement oidc logout
await (await Credential.getDefault())?.revoke();
}

export function useAuth () {
const router = useRouter();
const pathname = usePathname();

const signIn = useCallback(async () => {
const id = await performSignIn();
console.log('pathname: ', pathname);
return id;
}, [router]);

Expand All @@ -68,5 +18,9 @@ export function useAuth () {
router.navigate(redirectTo);
}, [router]);

return { signIn, signOut };
const handleAuthFlowExchange = useCallback(async (params: URLSearchParams) => {
return await handleAuthFlowCallback(params);
}, [])

return { signIn, signOut, handleAuthFlowExchange };
};
6 changes: 6 additions & 0 deletions e2e/apps/react-native-oidc/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,14 @@ import '@expo/metro-runtime';
import 'expo-router/entry';

import { Platform, installWebCryptoPolyfill } from '@okta/react-native-platform';
import { Linking } from 'react-native';
installWebCryptoPolyfill();

// Global deeplink debugging - log ALL deeplinks received
Linking.addEventListener('url', ({ url }) => {
console.log('[GLOBAL DEEPLINK RECEIVED]', url);
});

console.log('Plat', Platform, Platform.TimeCoordinator)
console.log("globalThis.crypto", globalThis.crypto);
// global.crypto = global.crypto ?? globalThis.crypto;
Expand Down
1 change: 0 additions & 1 deletion e2e/apps/react-native-oidc/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@
"expo-status-bar": "~3.0.8",
"expo-symbols": "~1.0.7",
"expo-system-ui": "~6.0.8",
"expo-web-browser": "~15.0.9",
"react": "19.1.0",
"react-dom": "19.1.0",
"react-native": "0.81.5",
Expand Down
38 changes: 38 additions & 0 deletions e2e/apps/token-broker/src/component/TestCallback.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { useEffect, useState } from 'react';
import { useNavigate } from 'react-router';
import { handleAuthorizationCodeFlowResponse } from '@/auth';
import { Loading } from './Loading';

interface FlowCallbackProps {
loadingElement?: React.ReactElement
}

// prevents mutiple calls in strict mode
// https://react.dev/learn/you-might-not-need-an-effect#initializing-the-application
let flowResumed = false;

export const TestCallback: React.FC<FlowCallbackProps> = ({ loadingElement = (<Loading />) }) => {
const navigate = useNavigate();
const [callbackError, setCallbackError] = useState<Error | null>(null);

useEffect(() => {
// prevents mutiple calls in strict mode
if (!flowResumed) {
// handleAuthorizationCodeFlowResponse()
// .then((originalUri) => {
// navigate(originalUri ?? '/', { replace: true });
// })
// .catch(err => {
// console.log(err, err.message);
// setCallbackError(err as unknown as Error);
// });
const url = new URL(window.location.href);
url.pathname = '/login/callback2';
window.location.replace(url.toString());

flowResumed = true;
}
}, []);

return loadingElement;
};
13 changes: 1 addition & 12 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,18 +32,7 @@
],
"nohoist": [
"@repo/okta-client-js-docs/**",
"**/typedoc",
"**/expo",
"**/expo/**",
"**/expo-*",
"**/expo-*/**",
"**/@expo/**",
"**/@expo/**/**",
"**/@react-navigation/**",
"react",
"react-native",
"react-native-oidc/@okta/*",
"react-native-oidc/@okta/**"
"**/typedoc"
]
},
"devEngines": {
Expand Down
Loading