├── e2e
├── .gitattributes
├── ios
│ ├── .xcode.env
│ ├── E2EOktaReactNative
│ │ ├── Images.xcassets
│ │ │ ├── Contents.json
│ │ │ ├── AppIcon.appiconset
│ │ │ │ ├── 100.png
│ │ │ │ ├── 1024.png
│ │ │ │ ├── 114.png
│ │ │ │ ├── 120.png
│ │ │ │ ├── 144.png
│ │ │ │ ├── 152.png
│ │ │ │ ├── 167.png
│ │ │ │ ├── 180.png
│ │ │ │ ├── 20.png
│ │ │ │ ├── 29.png
│ │ │ │ ├── 40.png
│ │ │ │ ├── 50.png
│ │ │ │ ├── 57.png
│ │ │ │ ├── 58.png
│ │ │ │ ├── 60.png
│ │ │ │ ├── 72.png
│ │ │ │ ├── 76.png
│ │ │ │ ├── 80.png
│ │ │ │ ├── 87.png
│ │ │ │ ├── App-Icon-1024x1024@1x.png
│ │ │ │ └── Contents.json
│ │ │ ├── SplashScreenLogo.imageset
│ │ │ │ ├── image.png
│ │ │ │ ├── image@2x.png
│ │ │ │ ├── image@3x.png
│ │ │ │ ├── dark_image.png
│ │ │ │ ├── dark_image@2x.png
│ │ │ │ ├── dark_image@3x.png
│ │ │ │ └── Contents.json
│ │ │ ├── SplashScreenBackground.imageset
│ │ │ │ ├── image.png
│ │ │ │ └── Contents.json
│ │ │ └── SplashScreenBackground.colorset
│ │ │ │ └── Contents.json
│ │ ├── noop-file.swift
│ │ ├── E2EOktaReactNative-Bridging-Header.h
│ │ ├── E2EOktaReactNative.entitlements
│ │ ├── Supporting
│ │ │ └── Expo.plist
│ │ ├── AppDelegate.h
│ │ ├── main.m
│ │ ├── PrivacyInfo.xcprivacy
│ │ ├── Info.plist
│ │ ├── AppDelegate.mm
│ │ ├── SplashScreen.storyboard
│ │ └── Base.lproj
│ │ │ └── LaunchScreen.xib
│ ├── Podfile.properties.json
│ ├── .gitignore
│ ├── E2EOktaReactNative-Bridging-Header.h
│ ├── Dummy.swift
│ ├── E2EOktaReactNativeUITests
│ │ ├── Info.plist
│ │ ├── ABColdStartTests.swift
│ │ ├── LoginTests.swift
│ │ ├── CustomLoginTests.swift
│ │ └── BrowserLoginTests.swift
│ ├── Podfile
│ └── E2EOktaReactNative.xcodeproj
│ │ └── xcshareddata
│ │ └── xcschemes
│ │ └── E2EOktaReactNative.xcscheme
├── app_logo.png
├── android
│ ├── app
│ │ ├── debug.keystore
│ │ ├── src
│ │ │ ├── main
│ │ │ │ ├── res
│ │ │ │ │ ├── values-night
│ │ │ │ │ │ └── colors.xml
│ │ │ │ │ ├── mipmap-hdpi
│ │ │ │ │ │ ├── ic_launcher.webp
│ │ │ │ │ │ └── ic_launcher_round.webp
│ │ │ │ │ ├── mipmap-mdpi
│ │ │ │ │ │ ├── ic_launcher.webp
│ │ │ │ │ │ └── ic_launcher_round.webp
│ │ │ │ │ ├── mipmap-xhdpi
│ │ │ │ │ │ ├── ic_launcher.webp
│ │ │ │ │ │ └── ic_launcher_round.webp
│ │ │ │ │ ├── mipmap-xxhdpi
│ │ │ │ │ │ ├── ic_launcher.webp
│ │ │ │ │ │ └── ic_launcher_round.webp
│ │ │ │ │ ├── mipmap-xxxhdpi
│ │ │ │ │ │ ├── ic_launcher.webp
│ │ │ │ │ │ └── ic_launcher_round.webp
│ │ │ │ │ ├── drawable-hdpi
│ │ │ │ │ │ └── splashscreen_logo.png
│ │ │ │ │ ├── drawable-mdpi
│ │ │ │ │ │ └── splashscreen_logo.png
│ │ │ │ │ ├── drawable-xhdpi
│ │ │ │ │ │ └── splashscreen_logo.png
│ │ │ │ │ ├── drawable-xxhdpi
│ │ │ │ │ │ └── splashscreen_logo.png
│ │ │ │ │ ├── drawable-xxxhdpi
│ │ │ │ │ │ └── splashscreen_logo.png
│ │ │ │ │ ├── drawable-night-hdpi
│ │ │ │ │ │ └── splashscreen_logo.png
│ │ │ │ │ ├── drawable-night-mdpi
│ │ │ │ │ │ └── splashscreen_logo.png
│ │ │ │ │ ├── drawable-night-xhdpi
│ │ │ │ │ │ └── splashscreen_logo.png
│ │ │ │ │ ├── drawable-night-xxhdpi
│ │ │ │ │ │ └── splashscreen_logo.png
│ │ │ │ │ ├── drawable-night-xxxhdpi
│ │ │ │ │ │ └── splashscreen_logo.png
│ │ │ │ │ ├── values
│ │ │ │ │ │ ├── colors.xml
│ │ │ │ │ │ ├── strings.xml
│ │ │ │ │ │ └── styles.xml
│ │ │ │ │ └── drawable
│ │ │ │ │ │ ├── ic_launcher_background.xml
│ │ │ │ │ │ └── rn_edit_text_material.xml
│ │ │ │ ├── AndroidManifest.xml
│ │ │ │ └── java
│ │ │ │ │ └── com
│ │ │ │ │ └── e2eoktareactnative
│ │ │ │ │ ├── MainApplication.kt
│ │ │ │ │ └── MainActivity.kt
│ │ │ ├── debug
│ │ │ │ └── AndroidManifest.xml
│ │ │ └── androidTest
│ │ │ │ └── java
│ │ │ │ └── com
│ │ │ │ └── e2eoktareactnative
│ │ │ │ ├── test
│ │ │ │ ├── AdbUtil.kt
│ │ │ │ ├── EndToEndCredentials.kt
│ │ │ │ └── UiAutomationHelpers.kt
│ │ │ │ ├── dashboard
│ │ │ │ └── DashboardPage.kt
│ │ │ │ ├── login
│ │ │ │ ├── LoginPage.kt
│ │ │ │ ├── CustomLoginTest.kt
│ │ │ │ └── BrowserLoginTest.kt
│ │ │ │ ├── customlogin
│ │ │ │ └── CustomLoginPage.kt
│ │ │ │ └── web
│ │ │ │ └── WebPage.kt
│ │ └── proguard-rules.pro
│ ├── gradle
│ │ └── wrapper
│ │ │ ├── gradle-wrapper.jar
│ │ │ └── gradle-wrapper.properties
│ ├── .gitignore
│ ├── runTestsInFirebaseTestLab.sh
│ ├── licenseTemplate.txt
│ ├── forceVersions.gradle
│ ├── settings.gradle
│ ├── build.gradle
│ ├── gradle.properties
│ └── gradlew.bat
├── app.json
├── metro.config.js
├── index.js
├── babel.config.js
├── package.json
├── config.js
├── App.js
└── pages
│ ├── ProfilePage.js
│ ├── CustomLogin.js
│ └── Home.js
├── ios
├── .xcode.env
├── Podfile
├── Tests
│ ├── Info.plist
│ ├── Mocks
│ │ ├── OktaSdkBridgeMock.swift
│ │ ├── OktaOidcStateManagerMock.swift
│ │ ├── OktaOidcMock.swift
│ │ └── OktaOidcStateManager+Factory.swift
│ ├── OktaSdkConstantTests.swift
│ └── OktaReactNativeErrorTests.swift
├── OktaSdkBridge
│ ├── ReactNativeOktaSdkBridge-Bridging-Header.h
│ ├── OktaSdkConstant.swift
│ ├── OktaSDKError.swift
│ └── ReactNativeOktaSdkBridge.m
└── ReactNativeOktaSdkBridge.xcodeproj
│ └── xcshareddata
│ └── xcschemes
│ └── ReactNativeOktaSdkBridge.xcscheme
├── .gitattributes
├── .circleci
├── android_sdk_checksum
└── config.yml
├── android
├── src
│ └── main
│ │ ├── AndroidManifest.xml
│ │ └── java
│ │ └── com
│ │ └── oktareactnative
│ │ ├── OktaSdkBridgePackage.java
│ │ ├── OktaSdkError.java
│ │ ├── OktaSdkConstant.java
│ │ └── HttpClientImpl.java
├── gradle
│ └── wrapper
│ │ ├── gradle-wrapper.jar
│ │ └── gradle-wrapper.properties
├── forceVersions.gradle
├── gradle.properties
├── gradlew.bat
└── build.gradle
├── types
├── tslint.json
├── tsconfig.json
├── index.test-d.ts
└── index.d.ts
├── babel.config.js
├── scripts
├── sast_scan.sh
├── lint.sh
├── unit.sh
├── snyk.sh
├── publish.sh
├── setup.sh
└── build.js
├── .github
├── ISSUE_TEMPLATE
│ ├── config.yml
│ ├── feature-request.yml
│ └── bug-report.yml
├── SECURITY.md
├── PULL_REQUEST_TEMPLATE
│ └── PULL_REQUEST_TEMPLATE.md
└── workflows
│ └── composite
│ └── configure-node
│ └── action.yml
├── jsconfig.json
├── .vscode
└── launch.json
├── setupJest.js
├── OktaSdkBridgeReactNative.podspec
├── .gitignore
├── .bacon.yml
├── .eslintrc.js
├── CONTRIBUTING.md
└── package.json
/e2e/.gitattributes:
--------------------------------------------------------------------------------
1 | *.pbxproj -text
2 |
--------------------------------------------------------------------------------
/ios/.xcode.env:
--------------------------------------------------------------------------------
1 | export NODE_BINARY=$(command -v node)
2 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | *.cjs filter=lfs diff=lfs merge=lfs -text
2 |
--------------------------------------------------------------------------------
/e2e/ios/.xcode.env:
--------------------------------------------------------------------------------
1 | export NODE_BINARY=$(command -v node)
2 |
--------------------------------------------------------------------------------
/e2e/app_logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/okta/okta-react-native/HEAD/e2e/app_logo.png
--------------------------------------------------------------------------------
/e2e/android/app/debug.keystore:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/okta/okta-react-native/HEAD/e2e/android/app/debug.keystore
--------------------------------------------------------------------------------
/.circleci/android_sdk_checksum:
--------------------------------------------------------------------------------
1 | 2d2d50857e4eb553af5a6dc3ad507a17adf43d115264b1afc116f95c92e5e258 android-commandline.zip
2 |
--------------------------------------------------------------------------------
/android/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/types/tslint.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "dtslint/dtslint.json",
3 | "rules": {
4 | "no-useless-files": false
5 | }
6 | }
--------------------------------------------------------------------------------
/android/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/okta/okta-react-native/HEAD/android/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/e2e/android/app/src/main/res/values-night/colors.xml:
--------------------------------------------------------------------------------
1 |
2 | #000000
3 |
--------------------------------------------------------------------------------
/e2e/ios/E2EOktaReactNative/Images.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "expo"
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/e2e/android/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/okta/okta-react-native/HEAD/e2e/android/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/e2e/ios/Podfile.properties.json:
--------------------------------------------------------------------------------
1 | {
2 | "expo.jsEngine": "hermes",
3 | "EX_DEV_CLIENT_NETWORK_INSPECTOR": "true",
4 | "newArchEnabled": "false"
5 | }
6 |
--------------------------------------------------------------------------------
/babel.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | presets: ['module:metro-react-native-babel-preset'],
3 | plugins: ['@babel/plugin-transform-async-to-generator']
4 | };
5 |
--------------------------------------------------------------------------------
/e2e/ios/E2EOktaReactNative/noop-file.swift:
--------------------------------------------------------------------------------
1 | //
2 | // @generated
3 | // A blank Swift file must be created for native modules with Swift files to work correctly.
4 | //
--------------------------------------------------------------------------------
/scripts/sast_scan.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | cd ${OKTA_HOME}/${REPO}
4 |
5 | if ! sast_scan;
6 | then
7 | exit ${FAILURE}
8 | fi
9 |
10 | exit ${SUCCESS}
11 |
--------------------------------------------------------------------------------
/e2e/android/app/src/main/res/mipmap-hdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/okta/okta-react-native/HEAD/e2e/android/app/src/main/res/mipmap-hdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/e2e/android/app/src/main/res/mipmap-mdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/okta/okta-react-native/HEAD/e2e/android/app/src/main/res/mipmap-mdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/e2e/android/app/src/main/res/mipmap-xhdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/okta/okta-react-native/HEAD/e2e/android/app/src/main/res/mipmap-xhdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/e2e/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/okta/okta-react-native/HEAD/e2e/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/e2e/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/okta/okta-react-native/HEAD/e2e/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/e2e/ios/E2EOktaReactNative/E2EOktaReactNative-Bridging-Header.h:
--------------------------------------------------------------------------------
1 | //
2 | // Use this file to import your target's public headers that you would like to expose to Swift.
3 | //
4 |
--------------------------------------------------------------------------------
/e2e/android/app/src/main/res/drawable-hdpi/splashscreen_logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/okta/okta-react-native/HEAD/e2e/android/app/src/main/res/drawable-hdpi/splashscreen_logo.png
--------------------------------------------------------------------------------
/e2e/android/app/src/main/res/drawable-mdpi/splashscreen_logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/okta/okta-react-native/HEAD/e2e/android/app/src/main/res/drawable-mdpi/splashscreen_logo.png
--------------------------------------------------------------------------------
/e2e/android/app/src/main/res/drawable-xhdpi/splashscreen_logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/okta/okta-react-native/HEAD/e2e/android/app/src/main/res/drawable-xhdpi/splashscreen_logo.png
--------------------------------------------------------------------------------
/e2e/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/okta/okta-react-native/HEAD/e2e/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/e2e/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/okta/okta-react-native/HEAD/e2e/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/e2e/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/okta/okta-react-native/HEAD/e2e/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/e2e/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/okta/okta-react-native/HEAD/e2e/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/e2e/android/app/src/main/res/drawable-xxhdpi/splashscreen_logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/okta/okta-react-native/HEAD/e2e/android/app/src/main/res/drawable-xxhdpi/splashscreen_logo.png
--------------------------------------------------------------------------------
/e2e/android/app/src/main/res/drawable-xxxhdpi/splashscreen_logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/okta/okta-react-native/HEAD/e2e/android/app/src/main/res/drawable-xxxhdpi/splashscreen_logo.png
--------------------------------------------------------------------------------
/e2e/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/okta/okta-react-native/HEAD/e2e/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/e2e/android/app/src/main/res/drawable-night-hdpi/splashscreen_logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/okta/okta-react-native/HEAD/e2e/android/app/src/main/res/drawable-night-hdpi/splashscreen_logo.png
--------------------------------------------------------------------------------
/e2e/android/app/src/main/res/drawable-night-mdpi/splashscreen_logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/okta/okta-react-native/HEAD/e2e/android/app/src/main/res/drawable-night-mdpi/splashscreen_logo.png
--------------------------------------------------------------------------------
/e2e/ios/E2EOktaReactNative/Images.xcassets/AppIcon.appiconset/100.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/okta/okta-react-native/HEAD/e2e/ios/E2EOktaReactNative/Images.xcassets/AppIcon.appiconset/100.png
--------------------------------------------------------------------------------
/e2e/ios/E2EOktaReactNative/Images.xcassets/AppIcon.appiconset/1024.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/okta/okta-react-native/HEAD/e2e/ios/E2EOktaReactNative/Images.xcassets/AppIcon.appiconset/1024.png
--------------------------------------------------------------------------------
/e2e/ios/E2EOktaReactNative/Images.xcassets/AppIcon.appiconset/114.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/okta/okta-react-native/HEAD/e2e/ios/E2EOktaReactNative/Images.xcassets/AppIcon.appiconset/114.png
--------------------------------------------------------------------------------
/e2e/ios/E2EOktaReactNative/Images.xcassets/AppIcon.appiconset/120.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/okta/okta-react-native/HEAD/e2e/ios/E2EOktaReactNative/Images.xcassets/AppIcon.appiconset/120.png
--------------------------------------------------------------------------------
/e2e/ios/E2EOktaReactNative/Images.xcassets/AppIcon.appiconset/144.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/okta/okta-react-native/HEAD/e2e/ios/E2EOktaReactNative/Images.xcassets/AppIcon.appiconset/144.png
--------------------------------------------------------------------------------
/e2e/ios/E2EOktaReactNative/Images.xcassets/AppIcon.appiconset/152.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/okta/okta-react-native/HEAD/e2e/ios/E2EOktaReactNative/Images.xcassets/AppIcon.appiconset/152.png
--------------------------------------------------------------------------------
/e2e/ios/E2EOktaReactNative/Images.xcassets/AppIcon.appiconset/167.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/okta/okta-react-native/HEAD/e2e/ios/E2EOktaReactNative/Images.xcassets/AppIcon.appiconset/167.png
--------------------------------------------------------------------------------
/e2e/ios/E2EOktaReactNative/Images.xcassets/AppIcon.appiconset/180.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/okta/okta-react-native/HEAD/e2e/ios/E2EOktaReactNative/Images.xcassets/AppIcon.appiconset/180.png
--------------------------------------------------------------------------------
/e2e/ios/E2EOktaReactNative/Images.xcassets/AppIcon.appiconset/20.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/okta/okta-react-native/HEAD/e2e/ios/E2EOktaReactNative/Images.xcassets/AppIcon.appiconset/20.png
--------------------------------------------------------------------------------
/e2e/ios/E2EOktaReactNative/Images.xcassets/AppIcon.appiconset/29.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/okta/okta-react-native/HEAD/e2e/ios/E2EOktaReactNative/Images.xcassets/AppIcon.appiconset/29.png
--------------------------------------------------------------------------------
/e2e/ios/E2EOktaReactNative/Images.xcassets/AppIcon.appiconset/40.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/okta/okta-react-native/HEAD/e2e/ios/E2EOktaReactNative/Images.xcassets/AppIcon.appiconset/40.png
--------------------------------------------------------------------------------
/e2e/ios/E2EOktaReactNative/Images.xcassets/AppIcon.appiconset/50.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/okta/okta-react-native/HEAD/e2e/ios/E2EOktaReactNative/Images.xcassets/AppIcon.appiconset/50.png
--------------------------------------------------------------------------------
/e2e/ios/E2EOktaReactNative/Images.xcassets/AppIcon.appiconset/57.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/okta/okta-react-native/HEAD/e2e/ios/E2EOktaReactNative/Images.xcassets/AppIcon.appiconset/57.png
--------------------------------------------------------------------------------
/e2e/ios/E2EOktaReactNative/Images.xcassets/AppIcon.appiconset/58.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/okta/okta-react-native/HEAD/e2e/ios/E2EOktaReactNative/Images.xcassets/AppIcon.appiconset/58.png
--------------------------------------------------------------------------------
/e2e/ios/E2EOktaReactNative/Images.xcassets/AppIcon.appiconset/60.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/okta/okta-react-native/HEAD/e2e/ios/E2EOktaReactNative/Images.xcassets/AppIcon.appiconset/60.png
--------------------------------------------------------------------------------
/e2e/ios/E2EOktaReactNative/Images.xcassets/AppIcon.appiconset/72.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/okta/okta-react-native/HEAD/e2e/ios/E2EOktaReactNative/Images.xcassets/AppIcon.appiconset/72.png
--------------------------------------------------------------------------------
/e2e/ios/E2EOktaReactNative/Images.xcassets/AppIcon.appiconset/76.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/okta/okta-react-native/HEAD/e2e/ios/E2EOktaReactNative/Images.xcassets/AppIcon.appiconset/76.png
--------------------------------------------------------------------------------
/e2e/ios/E2EOktaReactNative/Images.xcassets/AppIcon.appiconset/80.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/okta/okta-react-native/HEAD/e2e/ios/E2EOktaReactNative/Images.xcassets/AppIcon.appiconset/80.png
--------------------------------------------------------------------------------
/e2e/ios/E2EOktaReactNative/Images.xcassets/AppIcon.appiconset/87.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/okta/okta-react-native/HEAD/e2e/ios/E2EOktaReactNative/Images.xcassets/AppIcon.appiconset/87.png
--------------------------------------------------------------------------------
/e2e/android/app/src/main/res/drawable-night-xhdpi/splashscreen_logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/okta/okta-react-native/HEAD/e2e/android/app/src/main/res/drawable-night-xhdpi/splashscreen_logo.png
--------------------------------------------------------------------------------
/e2e/android/app/src/main/res/drawable-night-xxhdpi/splashscreen_logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/okta/okta-react-native/HEAD/e2e/android/app/src/main/res/drawable-night-xxhdpi/splashscreen_logo.png
--------------------------------------------------------------------------------
/e2e/android/app/src/main/res/drawable-night-xxxhdpi/splashscreen_logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/okta/okta-react-native/HEAD/e2e/android/app/src/main/res/drawable-night-xxxhdpi/splashscreen_logo.png
--------------------------------------------------------------------------------
/e2e/ios/E2EOktaReactNative/Images.xcassets/SplashScreenLogo.imageset/image.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/okta/okta-react-native/HEAD/e2e/ios/E2EOktaReactNative/Images.xcassets/SplashScreenLogo.imageset/image.png
--------------------------------------------------------------------------------
/e2e/ios/E2EOktaReactNative/Images.xcassets/SplashScreenLogo.imageset/image@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/okta/okta-react-native/HEAD/e2e/ios/E2EOktaReactNative/Images.xcassets/SplashScreenLogo.imageset/image@2x.png
--------------------------------------------------------------------------------
/e2e/ios/E2EOktaReactNative/Images.xcassets/SplashScreenLogo.imageset/image@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/okta/okta-react-native/HEAD/e2e/ios/E2EOktaReactNative/Images.xcassets/SplashScreenLogo.imageset/image@3x.png
--------------------------------------------------------------------------------
/e2e/ios/E2EOktaReactNative/Images.xcassets/SplashScreenBackground.imageset/image.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/okta/okta-react-native/HEAD/e2e/ios/E2EOktaReactNative/Images.xcassets/SplashScreenBackground.imageset/image.png
--------------------------------------------------------------------------------
/e2e/ios/E2EOktaReactNative/Images.xcassets/SplashScreenLogo.imageset/dark_image.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/okta/okta-react-native/HEAD/e2e/ios/E2EOktaReactNative/Images.xcassets/SplashScreenLogo.imageset/dark_image.png
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/config.yml:
--------------------------------------------------------------------------------
1 | contact_links:
2 | - name: Developer Forum
3 | url: https://devforum.okta.com/
4 | about: Get help with building your application on the Okta Platform.
5 | blank_issues_enabled: false
6 |
--------------------------------------------------------------------------------
/e2e/ios/E2EOktaReactNative/Images.xcassets/AppIcon.appiconset/App-Icon-1024x1024@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/okta/okta-react-native/HEAD/e2e/ios/E2EOktaReactNative/Images.xcassets/AppIcon.appiconset/App-Icon-1024x1024@1x.png
--------------------------------------------------------------------------------
/e2e/ios/E2EOktaReactNative/Images.xcassets/SplashScreenLogo.imageset/dark_image@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/okta/okta-react-native/HEAD/e2e/ios/E2EOktaReactNative/Images.xcassets/SplashScreenLogo.imageset/dark_image@2x.png
--------------------------------------------------------------------------------
/e2e/ios/E2EOktaReactNative/Images.xcassets/SplashScreenLogo.imageset/dark_image@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/okta/okta-react-native/HEAD/e2e/ios/E2EOktaReactNative/Images.xcassets/SplashScreenLogo.imageset/dark_image@3x.png
--------------------------------------------------------------------------------
/e2e/android/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 | #ffffff
3 | #023c69
4 | #ffffff
5 |
--------------------------------------------------------------------------------
/jsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "ES6"
4 | },
5 | "typeAcquisition": {
6 | "include": [
7 | "jest"
8 | ],
9 | },
10 | "exclude": [
11 | "node_modules",
12 | ]
13 | }
--------------------------------------------------------------------------------
/.github/SECURITY.md:
--------------------------------------------------------------------------------
1 | # Security Policy
2 |
3 | ## Report a Vulnerability
4 | At Okta we take the protection of our customers’ data very seriously. If you need to report a vulnerability, please visit https://www.okta.com/vulnerability-reporting-policy/ for more information.
5 |
--------------------------------------------------------------------------------
/e2e/android/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | E2E-Okta-React-Native
3 | contain
4 | false
5 |
--------------------------------------------------------------------------------
/android/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.12.1-all.zip
4 | networkTimeout=10000
5 | validateDistributionUrl=true
6 | zipStoreBase=GRADLE_USER_HOME
7 | zipStorePath=wrapper/dists
8 |
--------------------------------------------------------------------------------
/e2e/android/app/src/main/res/drawable/ic_launcher_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | -
4 |
5 |
6 |
--------------------------------------------------------------------------------
/e2e/android/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-all.zip
4 | networkTimeout=10000
5 | validateDistributionUrl=true
6 | zipStoreBase=GRADLE_USER_HOME
7 | zipStorePath=wrapper/dists
8 |
--------------------------------------------------------------------------------
/e2e/android/.gitignore:
--------------------------------------------------------------------------------
1 | # OSX
2 | #
3 | .DS_Store
4 |
5 | # Android/IntelliJ
6 | #
7 | build/
8 | .idea
9 | .gradle
10 | local.properties
11 | *.iml
12 | *.hprof
13 | .cxx/
14 |
15 | # Bundle artifacts
16 | *.jsbundle
17 | index.android.bundle
18 |
19 | # E2E credentials
20 | e2eCredentials.properties
21 | okta.properties
22 |
--------------------------------------------------------------------------------
/e2e/ios/E2EOktaReactNative/E2EOktaReactNative.entitlements:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | aps-environment
6 | development
7 |
8 |
--------------------------------------------------------------------------------
/e2e/ios/E2EOktaReactNative/Images.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images": [
3 | {
4 | "filename": "App-Icon-1024x1024@1x.png",
5 | "idiom": "universal",
6 | "platform": "ios",
7 | "size": "1024x1024"
8 | }
9 | ],
10 | "info": {
11 | "version": 1,
12 | "author": "expo"
13 | }
14 | }
--------------------------------------------------------------------------------
/e2e/android/app/src/debug/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/e2e/ios/E2EOktaReactNative/Supporting/Expo.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | EXUpdatesCheckOnLaunch
6 | ALWAYS
7 | EXUpdatesEnabled
8 |
9 | EXUpdatesLaunchWaitMs
10 | 0
11 |
12 |
--------------------------------------------------------------------------------
/e2e/ios/E2EOktaReactNative/Images.xcassets/SplashScreenBackground.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images": [
3 | {
4 | "idiom": "universal",
5 | "filename": "image.png",
6 | "scale": "1x"
7 | },
8 | {
9 | "idiom": "universal",
10 | "scale": "2x"
11 | },
12 | {
13 | "idiom": "universal",
14 | "scale": "3x"
15 | }
16 | ],
17 | "info": {
18 | "version": 1,
19 | "author": "expo"
20 | }
21 | }
--------------------------------------------------------------------------------
/e2e/ios/.gitignore:
--------------------------------------------------------------------------------
1 | # OSX
2 | #
3 | .DS_Store
4 |
5 | # Xcode
6 | #
7 | build/
8 | *.pbxuser
9 | !default.pbxuser
10 | *.mode1v3
11 | !default.mode1v3
12 | *.mode2v3
13 | !default.mode2v3
14 | *.perspectivev3
15 | !default.perspectivev3
16 | xcuserdata
17 | *.xccheckout
18 | *.moved-aside
19 | DerivedData
20 | *.hmap
21 | *.ipa
22 | *.xcuserstate
23 | project.xcworkspace
24 | .xcode.env.local
25 |
26 | # Bundle artifacts
27 | *.jsbundle
28 |
29 | # CocoaPods
30 | /Pods/
31 |
--------------------------------------------------------------------------------
/scripts/lint.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | source ${OKTA_HOME}/${REPO}/scripts/setup.sh
4 |
5 | export TEST_SUITE_TYPE="checkstyle"
6 | export TEST_RESULT_FILE_DIR="${REPO}/test-reports"
7 |
8 | if ! yarn lint:report; then
9 | echo "lint failed! Exiting..."
10 | exit ${TEST_FAILURE}
11 | fi
12 |
13 | echo ${TEST_SUITE_TYPE} > ${TEST_SUITE_TYPE_FILE}
14 | echo ${TEST_RESULT_FILE_DIR} > ${TEST_RESULT_FILE_DIR_FILE}
15 | exit ${PUBLISH_TYPE_AND_RESULT_DIR_BUT_SUCCEED_IF_NO_RESULTS}
16 |
--------------------------------------------------------------------------------
/scripts/unit.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | source ${OKTA_HOME}/${REPO}/scripts/setup.sh
4 |
5 | export TEST_SUITE_TYPE="junit"
6 | export TEST_RESULT_FILE_DIR="${REPO}/test-reports/unit"
7 |
8 | # Run jest with "ci" flag
9 | if ! yarn test --ci; then
10 | echo "unit failed! Exiting..."
11 | exit ${TEST_FAILURE}
12 | fi
13 |
14 | echo ${TEST_SUITE_TYPE} > ${TEST_SUITE_TYPE_FILE}
15 | echo ${TEST_RESULT_FILE_DIR} > ${TEST_RESULT_FILE_DIR_FILE}
16 | exit ${PUBLISH_TYPE_AND_RESULT_DIR}
17 |
--------------------------------------------------------------------------------
/android/forceVersions.gradle:
--------------------------------------------------------------------------------
1 | def forceVersions(ConfigurationContainer configurations) {
2 | configurations.configureEach { configuration ->
3 | configuration.resolutionStrategy {
4 | force 'org.bouncycastle:bcprov-jdk18on:1.78.1'
5 | force 'io.netty:netty-handler:4.1.125.Final'
6 | force 'io.netty:netty-codec-http:4.1.125.Final'
7 | force 'io.netty:netty-codec-http2:4.1.125.Final'
8 | force 'com.google.protobuf:protobuf-java:4.29.3'
9 | }
10 | }
11 | }
12 |
13 | ext.forceVersions = this.&forceVersions
14 |
--------------------------------------------------------------------------------
/ios/Podfile:
--------------------------------------------------------------------------------
1 | # Resolve react_native_pods.rb with node to allow for hoisting
2 | require Pod::Executable.execute_command('node', ['-p',
3 | 'require.resolve(
4 | "react-native/scripts/react_native_pods.rb",
5 | {paths: [process.argv[1]]},
6 | )', __dir__]).strip
7 |
8 | platform :ios, min_ios_version_supported
9 | prepare_react_native_project!
10 |
11 | def shared_pods
12 | use_react_native!(:hermes_enabled => false)
13 | pod 'OktaOidc'
14 | end
15 |
16 | target 'ReactNativeOktaSdkBridge' do
17 | shared_pods
18 | end
19 |
20 | target 'Tests' do
21 | shared_pods
22 | end
23 |
--------------------------------------------------------------------------------
/e2e/android/runTestsInFirebaseTestLab.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | set -e # Fail on error.
4 |
5 | gcloud firebase test android run \
6 | --no-auto-google-login \
7 | --type instrumentation \
8 | --app app/build/outputs/apk/debug/app-debug.apk \
9 | --test app/build/outputs/apk/androidTest/debug/app-debug-androidTest.apk \
10 | --device model=oriole,version=32,locale=en_US,orientation=portrait \
11 | --timeout 5m --no-performance-metrics \
12 | --use-orchestrator \
13 | --environment-variables clearPackageData=true \
14 | & PID_APP=$!
15 |
16 | wait $PID_APP
17 |
--------------------------------------------------------------------------------
/e2e/android/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in /usr/local/Cellar/android-sdk/24.3.3/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # react-native-reanimated
11 | -keep class com.swmansion.reanimated.** { *; }
12 | -keep class com.facebook.react.turbomodule.** { *; }
13 |
14 | # Add any project specific keep options here:
15 |
--------------------------------------------------------------------------------
/e2e/android/licenseTemplate.txt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright $YEAR-Present Okta, Inc.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
--------------------------------------------------------------------------------
/e2e/ios/E2EOktaReactNative-Bridging-Header.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2021-Present, Okta, Inc. and/or its affiliates. All rights reserved.
3 | * The Okta software accompanied by this notice is provided pursuant to the Apache License, Version 2.0 (the "License.")
4 | *
5 | * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0.
6 | * Unless required by applicable law or agreed to in writing, software
7 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
8 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
9 | *
10 | * See the License for the specific language governing permissions and limitations under the License.
11 | */
12 |
--------------------------------------------------------------------------------
/scripts/snyk.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | # When packages change their dependency tree, we want to run snyk monitor. This
4 | # sends the updated dependency tree to snyk for monitoring. We want to do this
5 | # when a commit has been made to master, not on PRs because the dependency tree
6 | # is likely still in flux while review is happening.
7 | #
8 | # For simplicity, this script just runs snyk monitor against all packages on
9 | # master commits, it doesn't try to figure out which packages were updated.
10 |
11 | if [[ "$TRAVIS_BRANCH" == "master" && "$TRAVIS_PULL_REQUEST" == "false" ]]; then
12 | yarn global add snyk
13 | snyk auth $SNYK_API_TOKEN
14 | echo "snyk monitor --org=$SNYK_ORG_ID"
15 | fi
16 |
--------------------------------------------------------------------------------
/.vscode/launch.json:
--------------------------------------------------------------------------------
1 | {
2 | // Use IntelliSense to learn about possible attributes.
3 | // Hover to view descriptions of existing attributes.
4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
5 | "version": "0.2.0",
6 | "configurations": [
7 | {
8 | "type": "node",
9 | "name": "Tests",
10 | "request": "launch",
11 | "program": "${workspaceFolder}/node_modules/jest/bin/jest",
12 | "args": [
13 | "--runInBand"
14 | ],
15 | "cwd": "${workspaceFolder}",
16 | "console": "integratedTerminal",
17 | "internalConsoleOptions": "neverOpen",
18 | "disableOptimisticBPs": true
19 | }
20 | ]
21 | }
--------------------------------------------------------------------------------
/e2e/app.json:
--------------------------------------------------------------------------------
1 | {
2 | "expo": {
3 | "name": "E2E-Okta-React-Native",
4 | "slug": "E2E-Okta-React-Native",
5 | "version": "1.0.0",
6 | "assetBundlePatterns": [
7 | "**/*"
8 | ],
9 | "android": {
10 | "package": "com.e2eoktareactnative"
11 | },
12 | "ios": {
13 | "bundleIdentifier": "com.e2eoktareactnative"
14 | },
15 | "plugins": [
16 | [
17 | "expo-splash-screen",
18 | {
19 | "backgroundColor": "#ffffff",
20 | "image": "./app_logo.png",
21 | "dark": {
22 | "image": "./app_logo.png",
23 | "backgroundColor": "#000000"
24 | },
25 | "imageWidth": 200
26 | }
27 | ]
28 | ]
29 | },
30 | "name": "E2E-Okta-React-Native"
31 | }
32 |
--------------------------------------------------------------------------------
/e2e/ios/Dummy.swift:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2021-Present, Okta, Inc. and/or its affiliates. All rights reserved.
3 | * The Okta software accompanied by this notice is provided pursuant to the Apache License, Version 2.0 (the "License.")
4 | *
5 | * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0.
6 | * Unless required by applicable law or agreed to in writing, software
7 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
8 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
9 | *
10 | * See the License for the specific language governing permissions and limitations under the License.
11 | */
12 |
13 | // This is a dummy file to compile CocoaPods and tests. Because React Native project is created as Obj-C project.
14 |
--------------------------------------------------------------------------------
/types/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "module": "commonjs",
4 | "lib": [
5 | "es6"
6 | ],
7 | "noEmit": true,
8 | "strict": true,
9 | "alwaysStrict": true,
10 | "noUnusedParameters": true,
11 | "noImplicitReturns": true,
12 | "noFallthroughCasesInSwitch": true,
13 | "allowJs": true,
14 | "allowSyntheticDefaultImports": true,
15 | "esModuleInterop": true,
16 | "isolatedModules": true,
17 | "jsx": "react-native",
18 | "moduleResolution": "node",
19 | "target": "esnext",
20 | "baseUrl": "./",
21 | "paths": {
22 | "OktaSDK": [
23 | "../"
24 | ]
25 | }
26 | },
27 | "exclude": [
28 | "node_modules",
29 | "babel.config.js",
30 | "metro.config.js",
31 | "jest.config.js"
32 | ]
33 | }
--------------------------------------------------------------------------------
/ios/Tests/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | $(PRODUCT_BUNDLE_PACKAGE_TYPE)
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 |
22 |
23 |
--------------------------------------------------------------------------------
/setupJest.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2019, Okta, Inc. and/or its affiliates. All rights reserved.
3 | * The Okta software accompanied by this notice is provided pursuant to the Apache License, Version 2.0 (the "License.")
4 | *
5 | * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0.
6 | * Unless required by applicable law or agreed to in writing, software
7 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
8 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
9 | *
10 | * See the License for the specific language governing permissions and limitations under the License.
11 | */
12 | global.XMLHttpRequest = jest.fn();
13 | global.fetch = jest.fn();
14 |
15 | if (typeof window !== 'object') {
16 | global.window = global;
17 | global.window.navigator = {};
18 | }
--------------------------------------------------------------------------------
/e2e/ios/E2EOktaReactNativeUITests/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | $(PRODUCT_BUNDLE_PACKAGE_TYPE)
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 |
22 |
23 |
--------------------------------------------------------------------------------
/e2e/ios/E2EOktaReactNative/AppDelegate.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2021-Present, Okta, Inc. and/or its affiliates. All rights reserved.
3 | * The Okta software accompanied by this notice is provided pursuant to the Apache License, Version 2.0 (the "License.")
4 | *
5 | * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0.
6 | * Unless required by applicable law or agreed to in writing, software
7 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
8 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
9 | *
10 | * See the License for the specific language governing permissions and limitations under the License.
11 | */
12 |
13 | #import
14 | #import
15 | #import
16 |
17 | @interface AppDelegate : EXAppDelegateWrapper
18 |
19 | @end
20 |
--------------------------------------------------------------------------------
/ios/OktaSdkBridge/ReactNativeOktaSdkBridge-Bridging-Header.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2019-Present, Okta, Inc. and/or its affiliates. All rights reserved.
3 | * The Okta software accompanied by this notice is provided pursuant to the Apache License, Version 2.0 (the "License.")
4 | *
5 | * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0.
6 | * Unless required by applicable law or agreed to in writing, software
7 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
8 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
9 | *
10 | * See the License for the specific language governing permissions and limitations under the License.
11 | */
12 |
13 | #import
14 | #import
15 | #import
16 | #import
17 |
18 |
--------------------------------------------------------------------------------
/OktaSdkBridgeReactNative.podspec:
--------------------------------------------------------------------------------
1 | require "json"
2 |
3 | package = JSON.parse(File.read(File.join(__dir__, "package.json")))
4 | version = package['version']
5 | source = { :git => 'https://github.com/okta/okta-react-native.git' }
6 | source[:tag] = "@okta/okta-react-native@#{version}"
7 |
8 | Pod::Spec.new do |s|
9 | s.name = package['podname']
10 | s.version = version
11 | s.summary = package['description']
12 | s.license = package['license']
13 |
14 | s.authors = package['author']
15 | s.homepage = package['homepage']
16 | s.platform = :ios, '12.4'
17 | s.swift_version = '5.0'
18 |
19 | s.source = source
20 | s.source_files = 'ios/OktaSdkBridge/**/*.{h,m,swift}', 'packages/okta-react-native/ios/OktaSdkBridge/**/*.{h,m,swift}'
21 |
22 | s.dependency 'React'
23 | s.dependency 'OktaOidc', '3.11.7'
24 | end
25 |
--------------------------------------------------------------------------------
/android/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 |
3 | # IDE (e.g. Android Studio) users:
4 | # Gradle settings configured through the IDE *will override*
5 | # any settings specified in this file.
6 |
7 | # For more details on how to configure your build environment visit
8 | # http://www.gradle.org/docs/current/userguide/build_environment.html
9 |
10 | # Specifies the JVM arguments used for the daemon process.
11 | # The setting is particularly useful for tweaking memory settings.
12 | org.gradle.jvmargs=-Xmx2048m
13 |
14 | # When configured, Gradle will run in incubating parallel mode.
15 | # This option should only be used with decoupled projects. More details, visit
16 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
17 | # org.gradle.parallel=true
18 | android.useAndroidX=true
19 | android.enableJetifier=true
20 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | /test-reports
3 | /dist
4 | node_modules
5 | npm-debug.log
6 | yarn-error.*
7 | .env
8 | *.hprof
9 | .idea/
10 | .yarn/install-state.gz
11 | e2e/.yarn/install-state.gz
12 |
13 | .watchmanconfig
14 |
15 | .vscode
16 | !.vscode/launch.json
17 |
18 | # Expo
19 | .expo/
20 | web-build/
21 |
22 | # Android/iOS related for react native
23 | .gradle/
24 | build/
25 | local.properties
26 | *.iml
27 | xcuserdata/
28 | e2e/ios/main.jsbundle
29 | e2e/android/app/src/main/java/com/e2eoktareactnative/generated/
30 |
31 | # General
32 | *.swp
33 | *.swo
34 | *.rbo
35 | *.gem
36 | .DS_Store
37 | .rbenv-version
38 | xcuserdata
39 | *.xcworkspace/
40 | ReactNativeOktaSdkBridge.xcworkspace
41 | DerivedData
42 | /.build
43 |
44 | # Xcode
45 | *.xccheckout
46 |
47 | ## Obj-C/Swift specific
48 | *.hmap
49 |
50 | ## App packaging
51 | *.ipa
52 | *.dSYM.zip
53 | *.dSYM
54 |
55 | # CocoaPods
56 | Pods/
57 |
--------------------------------------------------------------------------------
/e2e/metro.config.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2021-Present, Okta, Inc. and/or its affiliates. All rights reserved.
3 | * The Okta software accompanied by this notice is provided pursuant to the Apache License, Version 2.0 (the "License.")
4 | *
5 | * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0.
6 | * Unless required by applicable law or agreed to in writing, software
7 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
8 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
9 | *
10 | * See the License for the specific language governing permissions and limitations under the License.
11 | */
12 |
13 | /* eslint-disable node/no-missing-import */
14 |
15 | // Learn more https://docs.expo.io/guides/customizing-metro
16 | const { getDefaultConfig } = require('expo/metro-config');
17 |
18 | module.exports = getDefaultConfig(__dirname);
19 |
--------------------------------------------------------------------------------
/e2e/ios/E2EOktaReactNative/main.m:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2021-Present, Okta, Inc. and/or its affiliates. All rights reserved.
3 | * The Okta software accompanied by this notice is provided pursuant to the Apache License, Version 2.0 (the "License.")
4 | *
5 | * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0.
6 | * Unless required by applicable law or agreed to in writing, software
7 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
8 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
9 | *
10 | * See the License for the specific language governing permissions and limitations under the License.
11 | */
12 |
13 | #import
14 |
15 | #import "AppDelegate.h"
16 |
17 | int main(int argc, char * argv[]) {
18 | @autoreleasepool {
19 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
20 | }
21 | }
22 |
23 |
--------------------------------------------------------------------------------
/scripts/publish.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | source $OKTA_HOME/$REPO/scripts/setup.sh
4 |
5 | export TEST_SUITE_TYPE="build"
6 | export REGISTRY="${ARTIFACTORY_URL}/api/npm/npm-topic"
7 |
8 | # Install required dependencies
9 | export PATH="${PATH}:$(yarn global bin)"
10 | yarn global add @okta/ci-append-sha
11 |
12 | if [ -n "${action_branch}" ];
13 | then
14 | echo "Publishing from bacon task using branch ${action_branch}"
15 | TARGET_BRANCH=${action_branch}
16 | else
17 | echo "Publishing from bacon testSuite using branch ${BRANCH}"
18 | TARGET_BRANCH=${BRANCH}
19 | fi
20 |
21 | pushd ./dist
22 |
23 | if ! ci-append-sha; then
24 | echo "ci-append-sha failed! Exiting..."
25 | exit ${FAILED_SETUP}
26 | fi
27 |
28 | npm config set @okta:registry ${REGISTRY}
29 | if ! npm publish --registry ${REGISTRY}; then
30 | echo "npm publish failed! Exiting..."
31 | exit ${PUBLISH_ARTIFACTORY_FAILURE}
32 | fi
33 |
34 | popd
35 |
36 | exit $SUCCESS
37 |
--------------------------------------------------------------------------------
/e2e/android/app/src/androidTest/java/com/e2eoktareactnative/test/AdbUtil.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023-Present Okta, Inc.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.e2eoktareactnative.test
17 |
18 | import androidx.test.platform.app.InstrumentationRegistry.getInstrumentation
19 |
20 | fun execShellCommand(cmd: String) {
21 | getInstrumentation().uiAutomation.executeShellCommand(cmd).close()
22 | }
23 |
--------------------------------------------------------------------------------
/e2e/ios/E2EOktaReactNative/Images.xcassets/SplashScreenBackground.colorset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "colors": [
3 | {
4 | "color": {
5 | "components": {
6 | "alpha": "1.000",
7 | "blue": "1.00000000000000",
8 | "green": "1.00000000000000",
9 | "red": "1.00000000000000"
10 | },
11 | "color-space": "srgb"
12 | },
13 | "idiom": "universal"
14 | },
15 | {
16 | "color": {
17 | "components": {
18 | "alpha": "1.000",
19 | "blue": "0.00000000000000",
20 | "green": "0.00000000000000",
21 | "red": "0.00000000000000"
22 | },
23 | "color-space": "srgb"
24 | },
25 | "idiom": "universal",
26 | "appearances": [
27 | {
28 | "appearance": "luminosity",
29 | "value": "dark"
30 | }
31 | ]
32 | }
33 | ],
34 | "info": {
35 | "version": 1,
36 | "author": "expo"
37 | }
38 | }
--------------------------------------------------------------------------------
/.bacon.yml:
--------------------------------------------------------------------------------
1 | test_suites:
2 | - name: lint
3 | script_path: /root/okta/okta-react-native/scripts
4 | sort_order: '1'
5 | timeout: '60'
6 | script_name: lint
7 | criteria: MERGE
8 | queue_name: ci-queue-productionJenga-AL2023
9 | - name: unit
10 | script_path: /root/okta/okta-react-native/scripts
11 | sort_order: '2'
12 | timeout: '10'
13 | script_name: unit
14 | criteria: MERGE
15 | queue_name: ci-queue-productionJenga-AL2023
16 | - name: publish
17 | script_path: /root/okta/okta-react-native/scripts
18 | sort_order: '3'
19 | timeout: '60'
20 | script_name: publish
21 | criteria: MERGE
22 | queue_name: ci-queue-productionJenga-AL2023
23 | - name: sast_scan
24 | script_path: /root/okta/okta-react-native/scripts
25 | script_name: sast_scan
26 | sort_order: '4'
27 | timeout: '200'
28 | criteria: MERGE
29 | queue_name: small
30 | trigger: AUTO
31 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature-request.yml:
--------------------------------------------------------------------------------
1 | name: Feature Request
2 | description: Request a new feature for this SDK?
3 | labels: [ enhancement ]
4 | body:
5 | - type: textarea
6 | id: description
7 | attributes:
8 | label: Describe the feature request?
9 | description: |
10 | Please leave a helpful description of the feature request here.
11 | validations:
12 | required: true
13 |
14 | - type: textarea
15 | id: resources
16 | attributes:
17 | label: New or Affected Resource(s)
18 | description: |
19 | Please list the new or affected resources
20 | validations:
21 | required: true
22 |
23 | - type: textarea
24 | id: documentation
25 | attributes:
26 | label: Provide a documentation link
27 | description: |
28 | Please provide any links to the documentation that is at
29 | https://developer.okta.com/. This will help us with this
30 | feature request.
31 |
32 | - type: textarea
33 | id: additional
34 | attributes:
35 | label: Additional Information?
36 |
--------------------------------------------------------------------------------
/e2e/index.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2021-Present, Okta, Inc. and/or its affiliates. All rights reserved.
3 | * The Okta software accompanied by this notice is provided pursuant to the Apache License, Version 2.0 (the "License.")
4 | *
5 | * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0.
6 | * Unless required by applicable law or agreed to in writing, software
7 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
8 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
9 | *
10 | * See the License for the specific language governing permissions and limitations under the License.
11 | */
12 |
13 | /* eslint-disable node/no-missing-import */
14 |
15 | import 'react-native-gesture-handler';
16 | import { registerRootComponent } from 'expo';
17 |
18 | import App from './App';
19 |
20 | // registerRootComponent calls AppRegistry.registerComponent('main', () => App);
21 | // It also ensures that whether you load the app in Expo Go or in a native build,
22 | // the environment is set up appropriately
23 | registerRootComponent(App);
24 |
--------------------------------------------------------------------------------
/e2e/android/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
14 |
19 |
--------------------------------------------------------------------------------
/e2e/babel.config.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2021-Present, Okta, Inc. and/or its affiliates. All rights reserved.
3 | * The Okta software accompanied by this notice is provided pursuant to the Apache License, Version 2.0 (the "License.")
4 | *
5 | * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0.
6 | * Unless required by applicable law or agreed to in writing, software
7 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
8 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
9 | *
10 | * See the License for the specific language governing permissions and limitations under the License.
11 | */
12 |
13 | module.exports = function(api) {
14 | api.cache(false);
15 | return {
16 | presets: ['babel-preset-expo'],
17 | plugins: [
18 | 'react-native-reanimated/plugin',
19 | [
20 | 'module:react-native-dotenv', {
21 | 'moduleName': '@env',
22 | 'path': '.env',
23 | 'blacklist': null,
24 | 'whitelist': null,
25 | 'safe': false,
26 | 'allowUndefined': true
27 | }
28 | ]
29 | ]
30 | };
31 | };
32 |
--------------------------------------------------------------------------------
/e2e/android/app/src/androidTest/java/com/e2eoktareactnative/test/EndToEndCredentials.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023-Present Okta, Inc.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.e2eoktareactnative.test
17 |
18 | import java.util.Properties
19 |
20 | object EndToEndCredentials {
21 | private val properties = Properties()
22 |
23 | init {
24 | val inputStream = EndToEndCredentials::class.java.classLoader!!.getResourceAsStream("e2eCredentials.properties")
25 | properties.load(inputStream)
26 | }
27 |
28 | operator fun get(key: String): String {
29 | return properties.getProperty(key)
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/e2e/android/forceVersions.gradle:
--------------------------------------------------------------------------------
1 | def forceVersions(ConfigurationContainer configurations) {
2 | configurations.configureEach { configuration ->
3 | configuration.resolutionStrategy {
4 | force 'commons-fileupload:commons-fileupload:1.6.0'
5 | force 'com.google.guava:guava:32.1.3-android'
6 | force 'org.xerial:sqlite-jdbc:3.44.1.0'
7 | force 'com.google.code.gson:gson:2.10.1'
8 | force 'org.json:json:20231013'
9 | force 'org.bouncycastle:bcutil-jdk15to18:1.78.1'
10 | force 'org.bouncycastle:bcprov-jdk15to18:1.78.1'
11 | force 'org.bouncycastle:bcprov-jdk18on:1.78.1'
12 | force 'org.robolectric:robolectric:4.12.2'
13 | force 'junit:junit:4.13.2'
14 | force 'commons-io:commons-io:2.15.1'
15 | force 'commons-codec:commons-codec:1.17.0'
16 | force 'io.netty:netty-handler:4.1.125.Final'
17 | force 'io.netty:netty-codec-http:4.1.125.Final'
18 | force 'io.netty:netty-codec-http2:4.1.125.Final'
19 | force 'com.google.protobuf:protobuf-java:3.25.6'
20 | }
21 | }
22 | }
23 |
24 | ext.forceVersions = this.&forceVersions
25 |
--------------------------------------------------------------------------------
/e2e/android/app/src/androidTest/java/com/e2eoktareactnative/dashboard/DashboardPage.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023-Present Okta, Inc.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.e2eoktareactnative.dashboard
17 |
18 | import com.e2eoktareactnative.login.LoginPage
19 | import com.e2eoktareactnative.test.clickButtonWithText
20 | import com.e2eoktareactnative.test.waitForTextMatching
21 |
22 | internal class DashboardPage {
23 | init {
24 | waitForTextMatching("Welcome back, .*!")
25 | waitForTextMatching("User: .*")
26 | }
27 |
28 | fun logout(): LoginPage {
29 | clickButtonWithText("LOGOUT")
30 | return LoginPage()
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/.github/PULL_REQUEST_TEMPLATE/PULL_REQUEST_TEMPLATE.md:
--------------------------------------------------------------------------------
1 | ## PR Checklist
2 | Please check if your PR fulfills the following requirements:
3 |
4 | - [ ] The commit message follows our [guidelines](/okta/okta-react-native/blob/master/CONTRIBUTING.md#commit)
5 | - [ ] Tests for the changes have been added (for bug fixes / features)
6 | - [ ] Docs have been added / updated (for bug fixes / features)
7 |
8 |
9 | ## PR Type
10 | What kind of change does this PR introduce?
11 |
12 | - [ ] Bugfix
13 | - [ ] Feature
14 | - [ ] Code style update (formatting, local variables)
15 | - [ ] Refactoring (no functional changes, no api changes)
16 | - [ ] Adding Tests
17 | - [ ] Build related changes
18 | - [ ] CI related changes
19 | - [ ] Documentation changes
20 | - [ ] Other... Please describe:
21 |
22 |
23 | ## What is the current behavior?
24 |
25 |
26 | Issue Number: N/A
27 |
28 |
29 | ## What is the new behavior?
30 |
31 |
32 | ## Does this PR introduce a breaking change?
33 | - [ ] Yes
34 | - [ ] No
35 |
36 |
37 |
38 |
39 | ## Other information
40 |
41 |
42 | ## Reviewers
43 |
44 |
--------------------------------------------------------------------------------
/e2e/ios/E2EOktaReactNative/Images.xcassets/SplashScreenLogo.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images": [
3 | {
4 | "idiom": "universal",
5 | "filename": "image.png",
6 | "scale": "1x"
7 | },
8 | {
9 | "idiom": "universal",
10 | "filename": "image@2x.png",
11 | "scale": "2x"
12 | },
13 | {
14 | "idiom": "universal",
15 | "filename": "image@3x.png",
16 | "scale": "3x"
17 | },
18 | {
19 | "idiom": "universal",
20 | "appearances": [
21 | {
22 | "appearance": "luminosity",
23 | "value": "dark"
24 | }
25 | ],
26 | "scale": "1x",
27 | "filename": "dark_image.png"
28 | },
29 | {
30 | "idiom": "universal",
31 | "appearances": [
32 | {
33 | "appearance": "luminosity",
34 | "value": "dark"
35 | }
36 | ],
37 | "scale": "2x",
38 | "filename": "dark_image@2x.png"
39 | },
40 | {
41 | "idiom": "universal",
42 | "appearances": [
43 | {
44 | "appearance": "luminosity",
45 | "value": "dark"
46 | }
47 | ],
48 | "scale": "3x",
49 | "filename": "dark_image@3x.png"
50 | }
51 | ],
52 | "info": {
53 | "version": 1,
54 | "author": "expo"
55 | }
56 | }
--------------------------------------------------------------------------------
/e2e/ios/E2EOktaReactNativeUITests/ABColdStartTests.swift:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2021-Present, Okta, Inc. and/or its affiliates. All rights reserved.
3 | * The Okta software accompanied by this notice is provided pursuant to the Apache License, Version 2.0 (the "License.")
4 | *
5 | * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0.
6 | * Unless required by applicable law or agreed to in writing, software
7 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
8 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
9 | *
10 | * See the License for the specific language governing permissions and limitations under the License.
11 | */
12 |
13 | import XCTest
14 |
15 | // This test case launches first in test suite.
16 | // The problem that the first launch of application has more load due to initializing libraries and internal cache.
17 | // Because of naming this test case is the first in queue.
18 | final class ABColdStart: XCTestCase {
19 |
20 | private var app: XCUIApplication!
21 |
22 | override func setUpWithError() throws {
23 | app = XCUIApplication()
24 | app.launch()
25 | }
26 |
27 | func testABColdStart() {
28 | XCTAssertTrue(app.buttons.firstMatch.waitForExistence(timeout: .testing * 3))
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/scripts/setup.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | export NVM_DIR="/root/.nvm"
4 |
5 | # Install required node version
6 | setup_service node v20.9.0
7 |
8 | # determine the linux distro
9 | distro=$(awk -F= '$1=="ID" { print $2 ;}' /etc/os-release | tr -d '"')
10 | echo $distro
11 |
12 | # yarn installation is different, depending on distro
13 | if [ "$distro" = "centos" ]; then
14 | # Use the cacert bundled with centos as okta root CA is self-signed and cause issues downloading from yarn
15 | setup_service yarn 1.21.1 /etc/pki/tls/certs/ca-bundle.crt
16 | # Add yarn to the $PATH so npm cli commands do not fail
17 | export PATH="${PATH}:$(yarn global bin)"
18 | elif [ "$distro" = "amzn" ]; then
19 | yum install -y git-lfs
20 | git-lfs install
21 | npm install -g yarn
22 | export PATH="$PATH:$(npm config get prefix)/bin"
23 | else
24 | echo "Unknown OS environment, exiting..."
25 | exit ${FAILED_SETUP}
26 | fi
27 |
28 | cd ${OKTA_HOME}/${REPO}
29 |
30 | # undo permissions change on scripts/publish.sh
31 | git checkout -- scripts
32 |
33 | # ensure we're in a branch on the correct sha
34 | git checkout $BRANCH
35 | git-lfs pull
36 | git reset --hard $SHA
37 |
38 | git config --global user.email "oktauploader@okta.com"
39 | git config --global user.name "oktauploader-okta"
40 |
41 | if ! yarn install ; then
42 | echo "yarn install failed! Exiting..."
43 | exit ${FAILED_SETUP}
44 | fi
45 |
--------------------------------------------------------------------------------
/.github/workflows/composite/configure-node/action.yml:
--------------------------------------------------------------------------------
1 | name: 'Setup node, run yarn, cache node_modules'
2 | description: 'Checkout and run yarn install'
3 | author: 'okta'
4 |
5 | inputs:
6 | node-version:
7 | description: 'Node version'
8 | required: false
9 | default: 18
10 | node-path:
11 | description: 'Path to node_modules'
12 | required: true
13 | lock-hash:
14 | # We should pass a full hash because `hashFiles('${{ inputs.lock-path }}/yarn.lock')` doesn't work
15 | description: 'Hash of yarn.lock file'
16 | required: true
17 | install-path:
18 | description: 'yarn --cwd ${install-path} install'
19 | required: false
20 | default: ./
21 |
22 | outputs:
23 | cache-hit:
24 | description: "Cache node_files succeeded"
25 | value: ${{ steps.cache-node.outputs.cache-hit }}
26 |
27 | runs:
28 | using: "composite"
29 | steps:
30 | - name: Checkout
31 | uses: actions/setup-node@v3
32 | with:
33 | node-version: ${{ inputs.node-version }}
34 | - name: Install yarn
35 | run: npm install -g yarn
36 | shell: bash
37 | - name: Retrieve/save cache node_modules
38 | id: cache-node
39 | uses: actions/cache@v3
40 | with:
41 | path: ${{ inputs.node-path }}
42 | key: node-modules-${{ inputs.lock-hash }}
43 | - name: Install deps
44 | if: steps.cache-node.outputs.cache-hit != 'true'
45 | run: yarn --cwd ${{ inputs.install-path }} install --frozen-lockfile
46 | shell: bash
--------------------------------------------------------------------------------
/e2e/android/app/src/androidTest/java/com/e2eoktareactnative/login/LoginPage.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023-Present Okta, Inc.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.e2eoktareactnative.login
17 |
18 | import com.e2eoktareactnative.customlogin.CustomLoginPage
19 | import com.e2eoktareactnative.test.clickButtonWithText
20 | import com.e2eoktareactnative.test.waitForText
21 | import com.e2eoktareactnative.web.WebPage
22 | import kotlin.time.Duration.Companion.seconds
23 |
24 | internal class LoginPage {
25 | init {
26 | waitForText("BROWSER SIGN-IN", timeout = 10L.seconds.inWholeMilliseconds)
27 | }
28 |
29 | fun browserLogin(): WebPage {
30 | clickButtonWithText("BROWSER SIGN-IN")
31 | return WebPage(this)
32 | }
33 |
34 | fun customLogin(): CustomLoginPage {
35 | clickButtonWithText("CUSTOM SIGN-IN")
36 | return CustomLoginPage()
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/e2e/ios/E2EOktaReactNative/PrivacyInfo.xcprivacy:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | NSPrivacyAccessedAPITypes
6 |
7 |
8 | NSPrivacyAccessedAPIType
9 | NSPrivacyAccessedAPICategoryUserDefaults
10 | NSPrivacyAccessedAPITypeReasons
11 |
12 | CA92.1
13 |
14 |
15 |
16 | NSPrivacyAccessedAPIType
17 | NSPrivacyAccessedAPICategoryFileTimestamp
18 | NSPrivacyAccessedAPITypeReasons
19 |
20 | 0A2A.1
21 | 3B52.1
22 | C617.1
23 |
24 |
25 |
26 | NSPrivacyAccessedAPIType
27 | NSPrivacyAccessedAPICategoryDiskSpace
28 | NSPrivacyAccessedAPITypeReasons
29 |
30 | E174.1
31 | 85F4.1
32 |
33 |
34 |
35 | NSPrivacyAccessedAPIType
36 | NSPrivacyAccessedAPICategorySystemBootTime
37 | NSPrivacyAccessedAPITypeReasons
38 |
39 | 35F9.1
40 |
41 |
42 |
43 | NSPrivacyCollectedDataTypes
44 |
45 | NSPrivacyTracking
46 |
47 |
48 |
49 |
--------------------------------------------------------------------------------
/android/src/main/java/com/oktareactnative/OktaSdkBridgePackage.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2019, Okta, Inc. and/or its affiliates. All rights reserved.
3 | * The Okta software accompanied by this notice is provided pursuant to the Apache License, Version 2.0 (the "License.")
4 | *
5 | * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0.
6 | * Unless required by applicable law or agreed to in writing, software
7 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
8 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
9 | *
10 | * See the License for the specific language governing permissions and limitations under the License.
11 | */
12 |
13 | package com.oktareactnative;
14 |
15 | import java.util.Arrays;
16 | import java.util.Collections;
17 | import java.util.List;
18 |
19 | import com.facebook.react.ReactPackage;
20 | import com.facebook.react.bridge.NativeModule;
21 | import com.facebook.react.bridge.ReactApplicationContext;
22 | import com.facebook.react.uimanager.ViewManager;
23 | import com.facebook.react.bridge.JavaScriptModule;
24 |
25 | public class OktaSdkBridgePackage implements ReactPackage {
26 |
27 | @Override
28 | public List createNativeModules(ReactApplicationContext reactContext) {
29 | return Arrays.asList(new OktaSdkBridgeModule(reactContext));
30 | }
31 |
32 | @Override
33 | public List createViewManagers(ReactApplicationContext reactContext) {
34 | return Collections.emptyList();
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug-report.yml:
--------------------------------------------------------------------------------
1 | name: Bug Report
2 | description: Report a bug you encountered with the Okta React Native SDK
3 | labels: [ bug ]
4 | body:
5 | - type: textarea
6 | id: problem
7 | attributes:
8 | label: Describe the bug?
9 | description: |
10 | Please be as detailed as possible. This will help us address the bug in a timely manner.
11 | validations:
12 | required: true
13 |
14 | - type: textarea
15 | id: expected
16 | attributes:
17 | label: What is expected to happen?
18 | validations:
19 | required: true
20 |
21 | - type: textarea
22 | id: actual
23 | attributes:
24 | label: What is the actual behavior?
25 | validations:
26 | required: true
27 |
28 | - type: textarea
29 | id: repro
30 | attributes:
31 | label: Reproduction Steps?
32 | description: |
33 | Please provide as much detail as possible to help us reproduce your bug.
34 | A reproduction repo is very helpful for us as well.
35 | validations:
36 | required: true
37 |
38 | - type: textarea
39 | id: additional
40 | attributes:
41 | label: Additional Information?
42 |
43 | - type: textarea
44 | id: sdkVersion
45 | attributes:
46 | label: SDK Version
47 | validations:
48 | required: true
49 |
50 | - type: textarea
51 | id: buildInformation
52 | attributes:
53 | label: Build Information
54 | description: If this is an issue related to building, please supply relevant Android/Gradle/iOS/Xcode version information.
55 |
--------------------------------------------------------------------------------
/e2e/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "main": "index.js",
3 | "scripts": {
4 | "android": "expo run:android",
5 | "ios": "expo run:ios",
6 | "web": "expo start --web",
7 | "start": "expo start --dev-client",
8 | "bundle:ios": "react-native bundle --entry-file index.js --bundle-output ios/main.jsbundle --dev false --platform ios --assets-dest ios",
9 | "bundle:android": "mkdir -p android/app/src/main/assets; react-native bundle --entry-file index.js --bundle-output android/app/src/main/assets/index.android.bundle --dev false --platform android --assets-dest android/app/src/main/res"
10 | },
11 | "dependencies": {
12 | "@okta/okta-react-native": "file:../dist",
13 | "@react-navigation/native": "^6.1.17",
14 | "@react-navigation/native-stack": "^6.9.26",
15 | "expo": "^52.0.31",
16 | "expo-splash-screen": "~0.29.21",
17 | "expo-status-bar": "~2.0.1",
18 | "react": "18.3.1",
19 | "react-dom": "18.3.1",
20 | "react-native": "0.76.7",
21 | "react-native-dotenv": "^3.4.9",
22 | "react-native-gesture-handler": "~2.20.2",
23 | "react-native-reanimated": "^3.11.0",
24 | "react-native-safe-area-context": "4.12.0",
25 | "react-native-screens": "~4.4.0",
26 | "semver": "^7.6.2",
27 | "ws": "^8.18.0"
28 | },
29 | "resolutions": {
30 | "glob": "^9.3.5",
31 | "tar": "^6.2.1",
32 | "micromatch": "^4.0.7",
33 | "braces": "^3.0.3",
34 | "ws": "^8.18.0"
35 | },
36 | "devDependencies": {
37 | "@babel/core": "^7.24.6"
38 | },
39 | "private": true,
40 | "name": "e2e",
41 | "version": "1.0.0"
42 | }
43 |
--------------------------------------------------------------------------------
/ios/OktaSdkBridge/OktaSdkConstant.swift:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2019-Present, Okta, Inc. and/or its affiliates. All rights reserved.
3 | * The Okta software accompanied by this notice is provided pursuant to the Apache License, Version 2.0 (the "License.")
4 | *
5 | * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0.
6 | * Unless required by applicable law or agreed to in writing, software
7 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
8 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
9 | *
10 | * See the License for the specific language governing permissions and limitations under the License.
11 | */
12 |
13 | import Foundation
14 |
15 | struct OktaSdkConstant {
16 | /** ======== Keys ======== **/
17 | static let RESOLVE_TYPE_KEY = "resolve_type"
18 | static let ACCESS_TOKEN_KEY = "access_token"
19 | static let ID_TOKEN_KEY = "id_token"
20 | static let REFRESH_TOKEN_KEY = "refresh_token"
21 | static let AUTHENTICATED_KEY = "authenticated"
22 | static let ERROR_CODE_KEY = "error_code";
23 | static let ERROR_MSG_KEY = "error_message";
24 |
25 | /** ======== Values ======== **/
26 | static let AUTHORIZED = "authorized"
27 | static let SIGNED_OUT = "signed_out"
28 | static let CANCELLED = "cancelled"
29 |
30 | /** ======== Event names ======== **/
31 | static let SIGN_IN_SUCCESS = "signInSuccess";
32 | static let ON_ERROR = "onError";
33 | static let SIGN_OUT_SUCCESS = "signOutSuccess";
34 | static let ON_CANCELLED = "onCancelled";
35 | }
36 |
--------------------------------------------------------------------------------
/e2e/config.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2021-Present, Okta, Inc. and/or its affiliates. All rights reserved.
3 | * The Okta software accompanied by this notice is provided pursuant to the Apache License, Version 2.0 (the "License.")
4 | *
5 | * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0.
6 | * Unless required by applicable law or agreed to in writing, software
7 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
8 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
9 | *
10 | * See the License for the specific language governing permissions and limitations under the License.
11 | */
12 |
13 | /* eslint-disable node/no-missing-import */
14 |
15 | import { CLIENT_ID, REDIRECT_URI, LOGOUT_REDIRECT_URI, ISSUER } from '@env';
16 |
17 | /*
18 | clientId, redirectUri, endSessionRedirectUri - these values can be found on the "General" tab
19 | of the application that you created earlier in Admin Console.
20 | discoveryUri - this is the URL of the authorization server that will perform authentication.
21 |
22 | For more details, https://developer.okta.com/docs/guides/sign-into-mobile-app/create-okta-application/
23 | */
24 |
25 | export default {
26 | oidc: {
27 | clientId: CLIENT_ID, // e.g.: `a0abcEf0gH123ssJS4o5`
28 | redirectUri: REDIRECT_URI, // e.g.: `com.okta.example:/callback`
29 | endSessionRedirectUri: LOGOUT_REDIRECT_URI, // e.g.: com.okta.example:/logout
30 | discoveryUri: ISSUER, // e.g.: https://dev-1234.okta.com/
31 | scopes: ['openid', 'profile', 'offline_access'],
32 | requireHardwareBackedKeyStore: false,
33 | },
34 | };
35 |
--------------------------------------------------------------------------------
/e2e/android/settings.gradle:
--------------------------------------------------------------------------------
1 | pluginManagement {
2 | includeBuild(new File(["node", "--print", "require.resolve('@react-native/gradle-plugin/package.json', { paths: [require.resolve('react-native/package.json')] })"].execute(null, rootDir).text.trim()).getParentFile().toString())
3 | }
4 | plugins { id("com.facebook.react.settings") }
5 |
6 | extensions.configure(com.facebook.react.ReactSettingsExtension) { ex ->
7 | if (System.getenv('EXPO_USE_COMMUNITY_AUTOLINKING') == '1') {
8 | ex.autolinkLibrariesFromCommand()
9 | } else {
10 | def command = [
11 | 'node',
12 | '--no-warnings',
13 | '--eval',
14 | 'require(require.resolve(\'expo-modules-autolinking\', { paths: [require.resolve(\'expo/package.json\')] }))(process.argv.slice(1))',
15 | 'react-native-config',
16 | '--json',
17 | '--platform',
18 | 'android'
19 | ].toList()
20 | ex.autolinkLibrariesFromCommand(command)
21 | }
22 | }
23 |
24 | rootProject.name = 'E2E-Okta-React-Native'
25 |
26 | dependencyResolutionManagement {
27 | versionCatalogs {
28 | reactAndroidLibs {
29 | from(files(new File(["node", "--print", "require.resolve('react-native/package.json')"].execute(null, rootDir).text.trim(), "../gradle/libs.versions.toml")))
30 | }
31 | }
32 | }
33 |
34 | apply from: new File(["node", "--print", "require.resolve('expo/package.json')"].execute(null, rootDir).text.trim(), "../scripts/autolinking.gradle");
35 | useExpoModules()
36 |
37 | include ':app'
38 | includeBuild(new File(["node", "--print", "require.resolve('@react-native/gradle-plugin/package.json', { paths: [require.resolve('react-native/package.json')] })"].execute(null, rootDir).text.trim()).getParentFile())
39 |
--------------------------------------------------------------------------------
/e2e/App.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2021-Present, Okta, Inc. and/or its affiliates. All rights reserved.
3 | * The Okta software accompanied by this notice is provided pursuant to the Apache License, Version 2.0 (the "License.")
4 | *
5 | * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0.
6 | * Unless required by applicable law or agreed to in writing, software
7 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
8 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
9 | *
10 | * See the License for the specific language governing permissions and limitations under the License.
11 | */
12 |
13 | /* eslint-disable no-unused-vars */
14 | /* eslint-disable node/no-missing-import */
15 |
16 | import * as React from 'react';
17 | import { NavigationContainer } from '@react-navigation/native';
18 | import { createNativeStackNavigator } from '@react-navigation/native-stack';
19 | import CustomLogin from './pages/CustomLogin';
20 | import Home from './pages/Home';
21 | import ProfilePage from './pages/ProfilePage';
22 |
23 | const Stack = createNativeStackNavigator();
24 |
25 | const App = () => {
26 | return (
27 |
28 |
29 |
33 |
37 |
44 |
45 |
46 | );
47 | };
48 |
49 | export default App;
--------------------------------------------------------------------------------
/android/src/main/java/com/oktareactnative/OktaSdkError.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2019, Okta, Inc. and/or its affiliates. All rights reserved.
3 | * The Okta software accompanied by this notice is provided pursuant to the Apache License, Version 2.0 (the "License.")
4 | *
5 | * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0.
6 | * Unless required by applicable law or agreed to in writing, software
7 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
8 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
9 | *
10 | * See the License for the specific language governing permissions and limitations under the License.
11 | */
12 |
13 | package com.oktareactnative;
14 |
15 | public enum OktaSdkError {
16 | NOT_CONFIGURED("-100", "OktaOidc client isn't configured, check if you have created a configuration with createConfig"),
17 | NO_VIEW("-200", "No current view exists"),
18 | NO_ID_TOKEN("-500", "Id token does not exist"),
19 | OKTA_OIDC_ERROR("-600", "Okta Oidc error"),
20 | ERROR_TOKEN_TYPE("-700", "Token type not found"),
21 | NO_ACCESS_TOKEN("-900", "No access token found"),
22 | SIGN_IN_FAILED("-1000", "Sign in was not authorized"),
23 | NO_TOKENS("-1100", "Tokens not found"),
24 | CANCELLED("-1200", "User cancelled a session");
25 |
26 | private final String errorCode;
27 | private final String errorMessage;
28 |
29 | OktaSdkError(String errorCode, String errorMessage) {
30 | this.errorCode = errorCode;
31 | this.errorMessage = errorMessage;
32 | }
33 |
34 | String getErrorCode() {
35 | return errorCode;
36 | }
37 |
38 | String getErrorMessage() {
39 | return errorMessage;
40 | }
41 |
42 | }
43 |
--------------------------------------------------------------------------------
/ios/Tests/Mocks/OktaSdkBridgeMock.swift:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2021-Present, Okta, Inc. and/or its affiliates. All rights reserved.
3 | * The Okta software accompanied by this notice is provided pursuant to the Apache License, Version 2.0 (the "License.")
4 | *
5 | * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0.
6 | * Unless required by applicable law or agreed to in writing, software
7 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
8 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
9 | *
10 | * See the License for the specific language governing permissions and limitations under the License.
11 | */
12 |
13 | import XCTest
14 | import OktaOidc
15 | @testable import ReactNativeOktaSdkBridge
16 |
17 | final class OktaSdkBridgeMock: OktaSdkBridge {
18 | private(set) var eventsRegister: [String: Any] = [:]
19 | private var customStateManager: StateManagerProtocol?
20 |
21 | override var storedStateManager: StateManagerProtocol? {
22 | if customStateManager != nil {
23 | return customStateManager
24 | }
25 |
26 | return config.flatMap {
27 | OktaOidcStateManager.makeOidcStateManager(with: $0)
28 | }
29 | }
30 |
31 | func setCustomStateManager(_ stateManager: StateManagerProtocol) {
32 | self.customStateManager = stateManager
33 | }
34 |
35 | // Must be overriden
36 | override func supportedEvents() -> [String]! {
37 | super.supportedEvents()
38 | }
39 |
40 | override func sendEvent(withName name: String!, body: Any!) {
41 | eventsRegister[name] = body
42 | }
43 |
44 | override func presentedViewController() -> UIViewController? {
45 | UIViewController()
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/ios/Tests/OktaSdkConstantTests.swift:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2021-Present, Okta, Inc. and/or its affiliates. All rights reserved.
3 | * The Okta software accompanied by this notice is provided pursuant to the Apache License, Version 2.0 (the "License.")
4 | *
5 | * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0.
6 | * Unless required by applicable law or agreed to in writing, software
7 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
8 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
9 | *
10 | * See the License for the specific language governing permissions and limitations under the License.
11 | */
12 |
13 | import XCTest
14 | @testable import ReactNativeOktaSdkBridge
15 |
16 | final class OktaSdkConstantTests: XCTestCase {
17 | func testKeys() {
18 | XCTAssertEqual(OktaSdkConstant.RESOLVE_TYPE_KEY, "resolve_type")
19 | XCTAssertEqual(OktaSdkConstant.ACCESS_TOKEN_KEY, "access_token")
20 | XCTAssertEqual(OktaSdkConstant.ID_TOKEN_KEY, "id_token")
21 | XCTAssertEqual(OktaSdkConstant.REFRESH_TOKEN_KEY, "refresh_token")
22 | XCTAssertEqual(OktaSdkConstant.AUTHENTICATED_KEY, "authenticated")
23 | XCTAssertEqual(OktaSdkConstant.ERROR_CODE_KEY, "error_code")
24 | XCTAssertEqual(OktaSdkConstant.ERROR_MSG_KEY, "error_message")
25 | }
26 |
27 | func testValues() {
28 | XCTAssertEqual(OktaSdkConstant.AUTHORIZED, "authorized")
29 | XCTAssertEqual(OktaSdkConstant.SIGNED_OUT, "signed_out")
30 | XCTAssertEqual(OktaSdkConstant.CANCELLED, "cancelled")
31 | }
32 |
33 | func testEvents() {
34 | XCTAssertEqual(OktaSdkConstant.SIGN_IN_SUCCESS, "signInSuccess")
35 | XCTAssertEqual(OktaSdkConstant.ON_ERROR, "onError")
36 | XCTAssertEqual(OktaSdkConstant.SIGN_OUT_SUCCESS, "signOutSuccess")
37 | XCTAssertEqual(OktaSdkConstant.ON_CANCELLED, "onCancelled")
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/e2e/android/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 |
3 | buildscript {
4 | apply from: 'forceVersions.gradle'
5 | forceVersions(configurations)
6 |
7 | ext {
8 | buildToolsVersion = findProperty('android.buildToolsVersion') ?: '35.0.0'
9 | minSdkVersion = Integer.parseInt(findProperty('android.minSdkVersion') ?: '24')
10 | compileSdkVersion = Integer.parseInt(findProperty('android.compileSdkVersion') ?: '35')
11 | targetSdkVersion = Integer.parseInt(findProperty('android.targetSdkVersion') ?: '34')
12 | kotlinVersion = findProperty('android.kotlinVersion') ?: '1.9.25'
13 |
14 | ndkVersion = "26.1.10909125"
15 | }
16 | repositories {
17 | google()
18 | mavenCentral()
19 | }
20 | dependencies {
21 | classpath('com.android.tools.build:gradle')
22 | classpath('com.facebook.react:react-native-gradle-plugin')
23 | classpath('org.jetbrains.kotlin:kotlin-gradle-plugin')
24 | }
25 | }
26 |
27 | apply plugin: "com.facebook.react.rootproject"
28 |
29 | subprojects {
30 | task allDeps(type: DependencyReportTask) {}
31 | }
32 |
33 | allprojects {
34 | forceVersions(configurations)
35 |
36 | repositories {
37 | maven {
38 | // All of React Native (JS, Obj-C sources, Android binaries) is installed from npm
39 | url(new File(['node', '--print', "require.resolve('react-native/package.json')"].execute(null, rootDir).text.trim(), '../android'))
40 | }
41 | maven {
42 | // Android JSC is installed from npm
43 | url(new File(['node', '--print', "require.resolve('jsc-android/package.json', { paths: [require.resolve('react-native/package.json')] })"].execute(null, rootDir).text.trim(), '../dist'))
44 | }
45 |
46 | google()
47 | mavenCentral()
48 | maven { url 'https://www.jitpack.io' }
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/e2e/ios/E2EOktaReactNativeUITests/LoginTests.swift:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2021-Present, Okta, Inc. and/or its affiliates. All rights reserved.
3 | * The Okta software accompanied by this notice is provided pursuant to the Apache License, Version 2.0 (the "License.")
4 | *
5 | * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0.
6 | * Unless required by applicable law or agreed to in writing, software
7 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
8 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
9 | *
10 | * See the License for the specific language governing permissions and limitations under the License.
11 | */
12 |
13 | import XCTest
14 |
15 | extension TimeInterval {
16 |
17 | static let testing: TimeInterval = 15
18 | }
19 |
20 | class LoginTests: XCTestCase {
21 | let username = ProcessInfo.processInfo.environment["USERNAME"]!
22 | let password = ProcessInfo.processInfo.environment["PASSWORD"]!
23 |
24 | private(set) var app: XCUIApplication!
25 |
26 | var logoutButton: XCUIElement {
27 | app.buttons["logout_button"]
28 | }
29 |
30 | var browserLoginButton: XCUIElement {
31 | app.buttons["browser_login_button"]
32 | }
33 |
34 | var customLoginButton: XCUIElement {
35 | app.buttons["custom_login_button"]
36 | }
37 |
38 | var welcomeLabel: XCUIElement {
39 | app.staticTexts["welcome_text"]
40 | }
41 |
42 | var userNameLabel: XCUIElement {
43 | app.staticTexts["user_name"]
44 | }
45 |
46 | override func setUpWithError() throws {
47 | try super.setUpWithError()
48 |
49 | continueAfterFailure = false
50 |
51 | try XCTSkipIf(username.isEmpty, "Username is empty")
52 | try XCTSkipIf(password.isEmpty, "Password is empty")
53 |
54 | app = XCUIApplication()
55 | app.launch()
56 | }
57 |
58 | func testRootScreen() throws {
59 | // then
60 | XCTAssertTrue(browserLoginButton.waitForExistence(timeout: .testing))
61 | XCTAssertTrue(customLoginButton.exists)
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/e2e/android/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
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 |
--------------------------------------------------------------------------------
/e2e/android/app/src/main/res/drawable/rn_edit_text_material.xml:
--------------------------------------------------------------------------------
1 |
2 |
16 |
22 |
23 |
24 |
33 |
34 |
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/scripts/build.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const shell = require('shelljs');
4 | const path = require('path');
5 | const chalk = require('chalk');
6 | const fs = require('fs');
7 |
8 | const NPM_DIR = `dist`;
9 | const FILES_TO_COPY = [
10 | 'index.js',
11 | 'types/index.d.ts',
12 | 'android',
13 | 'ios/OktaSdkBridge',
14 | 'ios/ReactNativeOktaSdkBridge.xcodeproj',
15 | 'LICENSE',
16 | '*.md',
17 | 'package.json',
18 | 'OktaSdkBridgeReactNative.podspec'
19 | ];
20 |
21 | shell.echo(`Start building...`);
22 |
23 | shell.mkdir(`-p`, `${NPM_DIR}`);
24 |
25 | // Check whether a build folder isn't empty. If so, then delete any contents there.
26 | const folderSize = parseInt(shell.exec(`du -s ${NPM_DIR} | cut -f1`).stdout);
27 | const folderContents = shell.exec(`ls -A ${NPM_DIR}`).stdout;
28 | if ((folderSize && folderSize > 0) || (folderContents && folderContents != '')) {
29 | shell.echo(`Removing contents of build folder...`);
30 | shell.rm(`-Rf`, `${NPM_DIR}/*`);
31 | }
32 |
33 | // Create the nested folders to mirror files structure.
34 | FILES_TO_COPY.forEach(function(filePath) {
35 | const parentDir = path.join(NPM_DIR, path.dirname(filePath));
36 | if (parentDir != NPM_DIR) {
37 | shell.mkdir(`-p`, parentDir);
38 | }
39 |
40 | shell.cp(`-Rf`, filePath, parentDir);
41 | });
42 |
43 |
44 | shell.echo(`Modifying final package.json`);
45 | let packageJSON = JSON.parse(fs.readFileSync(`./${NPM_DIR}/package.json`));
46 | delete packageJSON.private; // remove private flag
47 | delete packageJSON.scripts; // remove all scripts
48 | delete packageJSON.jest; // remove jest section
49 | delete packageJSON['jest-junit']; // remove jest-junit section
50 | delete packageJSON.workspaces; // remove yarn workspace section
51 |
52 | // Remove "dist/" from the entrypoint paths.
53 | ['main', 'module', 'types'].forEach(function(key) {
54 | if (packageJSON[key]) {
55 | packageJSON[key] = packageJSON[key].replace(`${NPM_DIR}/`, '');
56 | }
57 | });
58 |
59 | fs.writeFileSync(`./${NPM_DIR}/package.json`, JSON.stringify(packageJSON, null, 4));
60 |
61 | shell.echo(chalk.green(`End building`));
62 |
--------------------------------------------------------------------------------
/e2e/android/app/src/androidTest/java/com/e2eoktareactnative/login/CustomLoginTest.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023-Present Okta, Inc.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.e2eoktareactnative.login
17 |
18 | import androidx.test.ext.junit.rules.activityScenarioRule
19 | import androidx.test.ext.junit.runners.AndroidJUnit4
20 | import com.e2eoktareactnative.MainActivity
21 | import com.e2eoktareactnative.test.EndToEndCredentials
22 | import org.junit.Rule
23 | import org.junit.Test
24 | import org.junit.runner.RunWith
25 |
26 | @RunWith(AndroidJUnit4::class)
27 | internal class CustomLoginTest {
28 | @get:Rule
29 | val activityRule = activityScenarioRule()
30 |
31 | private val testUsername = EndToEndCredentials.get("username")
32 | private val testPassword = EndToEndCredentials.get("password")
33 |
34 | @Test
35 | fun testCustomLogin() {
36 | LoginPage().customLogin()
37 | .username(testUsername)
38 | .password(testPassword)
39 | .login()
40 | }
41 |
42 | @Test
43 | fun testCustomLoginError() {
44 | LoginPage().customLogin()
45 | .username(testUsername)
46 | .password("wrongPassword")
47 | .loginExpectingError()
48 | .assertHasError("Sign in was not authorized")
49 | .pressAlertOkButton()
50 | }
51 |
52 | @Test
53 | fun testCustomLoginLogout() {
54 | LoginPage().customLogin()
55 | .username(testUsername)
56 | .password(testPassword)
57 | .login()
58 | .logout()
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/ios/Tests/Mocks/OktaOidcStateManagerMock.swift:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2021-Present, Okta, Inc. and/or its affiliates. All rights reserved.
3 | * The Okta software accompanied by this notice is provided pursuant to the Apache License, Version 2.0 (the "License.")
4 | *
5 | * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0.
6 | * Unless required by applicable law or agreed to in writing, software
7 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
8 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
9 | *
10 | * See the License for the specific language governing permissions and limitations under the License.
11 | */
12 |
13 | import XCTest
14 | import OktaOidc
15 | @testable import ReactNativeOktaSdkBridge
16 |
17 | final class OktaOidcStateManagerMock: StateManagerProtocol {
18 | var accessToken: String?
19 | var idToken: String?
20 | var refreshToken: String?
21 |
22 | private let shouldFail: Bool
23 | private let config: OktaOidcConfig
24 |
25 | init(shouldFail: Bool, config: OktaOidcConfig) {
26 | self.shouldFail = shouldFail
27 | self.config = config
28 | }
29 |
30 | func getUser(_ callback: @escaping ([String: Any]?, Error?) -> Void) {
31 | callback(shouldFail ? nil : ["name": "mock"],
32 | shouldFail ? OktaOidcError.noUserInfoEndpoint : nil)
33 | }
34 |
35 | func renew(callback: @escaping ((OktaOidcStateManager?, Error?) -> Void)) {
36 | callback(shouldFail ? nil : OktaOidcStateManager.makeOidcStateManager(with: config),
37 | shouldFail ? OktaOidcError.noRefreshToken : nil)
38 | }
39 |
40 | func revoke(_ token: String?, callback: @escaping (Bool, Error?) -> Void) {
41 | callback(!shouldFail, shouldFail ? OktaOidcError.noBearerToken : nil)
42 | }
43 |
44 | func introspect(token: String?, callback: @escaping ([String: Any]?, Error?) -> Void) {
45 | callback(shouldFail ? nil : ["exp": "mock"],
46 | shouldFail ? OktaOidcError.noBearerToken : nil)
47 | }
48 |
49 | func removeFromSecureStorage() throws {
50 |
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/ios/Tests/Mocks/OktaOidcMock.swift:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2021-Present, Okta, Inc. and/or its affiliates. All rights reserved.
3 | * The Okta software accompanied by this notice is provided pursuant to the Apache License, Version 2.0 (the "License.")
4 | *
5 | * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0.
6 | * Unless required by applicable law or agreed to in writing, software
7 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
8 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
9 | *
10 | * See the License for the specific language governing permissions and limitations under the License.
11 | */
12 |
13 | import XCTest
14 | import OktaOidc
15 | @testable import ReactNativeOktaSdkBridge
16 |
17 | class OktaOidcMock: OktaOidcProtocol {
18 | let configuration: OktaOidcConfig
19 |
20 | private let shouldFail: Bool
21 | private let oidcManager: OktaOidcStateManager
22 | private let failedError: Error?
23 |
24 | private var callbackError: Error {
25 | failedError ?? OktaReactNativeError.oktaOidcError
26 | }
27 |
28 | init(configuration: OktaOidcConfig, shouldFail: Bool, failedError: Error? = nil) {
29 | self.configuration = configuration
30 | self.shouldFail = shouldFail
31 | self.failedError = failedError
32 | self.oidcManager = OktaOidcStateManager.makeOidcStateManager(with: configuration)
33 | }
34 |
35 | func signInWithBrowser(from presenter: UIViewController,
36 | additionalParameters: [String: String],
37 | callback: @escaping ((OktaOidcStateManager?, Error?) -> Void)) {
38 | callback(shouldFail ? nil : oidcManager,
39 | shouldFail ? callbackError : nil)
40 | }
41 |
42 | func signOutOfOkta(_ authStateManager: OktaOidcStateManager, from presenter: UIViewController, callback: @escaping ((Error?) -> Void)) {
43 | callback(shouldFail ? callbackError : nil)
44 | }
45 |
46 | func authenticate(withSessionToken sessionToken: String, callback: @escaping ((OktaOidcStateManager?, Error?) -> Void)) {
47 | callback(shouldFail ? nil : oidcManager,
48 | shouldFail ? callbackError : nil)
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/e2e/android/app/src/main/java/com/e2eoktareactnative/MainApplication.kt:
--------------------------------------------------------------------------------
1 | package com.e2eoktareactnative
2 |
3 | import android.app.Application
4 | import android.content.res.Configuration
5 |
6 | import com.facebook.react.PackageList
7 | import com.facebook.react.ReactApplication
8 | import com.facebook.react.ReactNativeHost
9 | import com.facebook.react.ReactPackage
10 | import com.facebook.react.ReactHost
11 | import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint.load
12 | import com.facebook.react.defaults.DefaultReactNativeHost
13 | import com.facebook.react.soloader.OpenSourceMergedSoMapping
14 | import com.facebook.soloader.SoLoader
15 |
16 | import expo.modules.ApplicationLifecycleDispatcher
17 | import expo.modules.ReactNativeHostWrapper
18 |
19 | class MainApplication : Application(), ReactApplication {
20 |
21 | override val reactNativeHost: ReactNativeHost = ReactNativeHostWrapper(
22 | this,
23 | object : DefaultReactNativeHost(this) {
24 | override fun getPackages(): List {
25 | val packages = PackageList(this).packages
26 | // Packages that cannot be autolinked yet can be added manually here, for example:
27 | // packages.add(new MyReactNativePackage());
28 | return packages
29 | }
30 |
31 | override fun getJSMainModuleName(): String = ".expo/.virtual-metro-entry"
32 |
33 | override fun getUseDeveloperSupport(): Boolean = BuildConfig.DEBUG
34 |
35 | override val isNewArchEnabled: Boolean = BuildConfig.IS_NEW_ARCHITECTURE_ENABLED
36 | override val isHermesEnabled: Boolean = BuildConfig.IS_HERMES_ENABLED
37 | }
38 | )
39 |
40 | override val reactHost: ReactHost
41 | get() = ReactNativeHostWrapper.createReactHost(applicationContext, reactNativeHost)
42 |
43 | override fun onCreate() {
44 | super.onCreate()
45 | SoLoader.init(this, OpenSourceMergedSoMapping)
46 | if (BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) {
47 | // If you opted-in for the New Architecture, we load the native entry point for this app.
48 | load()
49 | }
50 | ApplicationLifecycleDispatcher.onApplicationCreate(this)
51 | }
52 |
53 | override fun onConfigurationChanged(newConfig: Configuration) {
54 | super.onConfigurationChanged(newConfig)
55 | ApplicationLifecycleDispatcher.onConfigurationChanged(this, newConfig)
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/e2e/android/app/src/androidTest/java/com/e2eoktareactnative/login/BrowserLoginTest.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023-Present Okta, Inc.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.e2eoktareactnative.login
17 |
18 | import androidx.test.ext.junit.rules.activityScenarioRule
19 | import androidx.test.ext.junit.runners.AndroidJUnit4
20 | import com.e2eoktareactnative.MainActivity
21 | import com.e2eoktareactnative.test.EndToEndCredentials
22 | import com.e2eoktareactnative.web.WebPage
23 | import org.junit.Before
24 | import org.junit.Rule
25 | import org.junit.Test
26 | import org.junit.runner.RunWith
27 |
28 | @RunWith(AndroidJUnit4::class)
29 | internal class BrowserLoginTest {
30 | @get:Rule
31 | val activityRule = activityScenarioRule()
32 |
33 | private val testUsername = EndToEndCredentials.get("username")
34 | private val testPassword = EndToEndCredentials.get("password")
35 |
36 | @Before
37 | fun clearWebData() {
38 | WebPage.clearData()
39 | }
40 |
41 | @Test
42 | fun testLoginPageExists() {
43 | LoginPage()
44 | }
45 |
46 | @Test
47 | fun testBrowserLogin() {
48 | LoginPage().browserLogin()
49 | .username(testUsername)
50 | .password(testPassword)
51 | .login()
52 | }
53 |
54 | @Test
55 | fun testFailedBrowserLogin() {
56 | LoginPage().browserLogin()
57 | .username(testUsername)
58 | .password("wrongPassword")
59 | .loginExpectingError()
60 | .assertHasError("Unable to sign in")
61 | .cancel()
62 | }
63 |
64 | @Test
65 | fun testBrowserLogout() {
66 | LoginPage().browserLogin()
67 | .username(testUsername)
68 | .password(testPassword)
69 | .login()
70 | .logout()
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/.circleci/config.yml:
--------------------------------------------------------------------------------
1 | version: 2.1
2 |
3 | orbs:
4 | general-platform-helpers: okta/general-platform-helpers@1.9
5 | node: circleci/node@5.1.0
6 |
7 | executors:
8 | linux:
9 | machine:
10 | image: ubuntu-2404:current
11 |
12 | commands:
13 | install_android_sdk:
14 | description: "Install Android SDK"
15 | steps:
16 | - run: wget --quiet --output-document="$HOME/android-commandline.zip" https://dl.google.com/android/repository/commandlinetools-linux-11076708_latest.zip
17 | - run: (cp .circleci/android_sdk_checksum $HOME/checksum; cd $HOME; shasum -a256 -c checksum)
18 | - run: set +o pipefail
19 | - run: unzip "$HOME/android-commandline.zip" -d "$HOME"
20 | - run: mkdir "$HOME/android-sdk"
21 | - run: echo y | $HOME/cmdline-tools/bin/sdkmanager --sdk_root="$HOME/android-sdk" "platforms;android-35" > /dev/null
22 | - run: echo y | $HOME/cmdline-tools/bin/sdkmanager --sdk_root="$HOME/android-sdk" "platform-tools" > /dev/null
23 | - run: echo y | $HOME/cmdline-tools/bin/sdkmanager --sdk_root="$HOME/android-sdk" "build-tools;35.0.0" > /dev/null
24 | - run: (yes || true) | $HOME/cmdline-tools/bin/sdkmanager --sdk_root="$HOME/android-sdk" --licenses
25 | - run: echo 'export ANDROID_HOME="$HOME/android-sdk"' >> "$BASH_ENV"
26 | - run: set -o pipefail
27 |
28 | setup:
29 | description: "Setup project for security scan"
30 | steps:
31 | - checkout
32 | - install_android_sdk
33 | - run: yarn install --frozen-lockfile
34 | - run: (cd android; ./gradlew assembleDebug) # Avoid gradle build during snyk scan
35 | - run: (cd e2e; yarn install --frozen-lockfile)
36 | - run: (cd e2e/android; echo "signInRedirectUri=com.example.redirect:/login" > okta.properties; ./gradlew assembleDebug) # Avoid gradle build during snyk scan
37 |
38 | jobs:
39 | snyk-scan:
40 | executor: linux
41 | steps:
42 | - setup
43 | - run: pip install setuptools
44 | - general-platform-helpers/step-load-dependencies
45 | - general-platform-helpers/step-run-snyk-monitor:
46 | run-on-non-main: true
47 | additional-arguments: --exclude=dist
48 |
49 | workflows:
50 | security-scan:
51 | jobs:
52 | - snyk-scan:
53 | name: execute-snyk
54 | context:
55 | - static-analysis
56 | filters:
57 | branches:
58 | only:
59 | - master
60 |
--------------------------------------------------------------------------------
/e2e/android/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 |
3 | # IDE (e.g. Android Studio) users:
4 | # Gradle settings configured through the IDE *will override*
5 | # any settings specified in this file.
6 |
7 | # For more details on how to configure your build environment visit
8 | # http://www.gradle.org/docs/current/userguide/build_environment.html
9 |
10 | # Specifies the JVM arguments used for the daemon process.
11 | # The setting is particularly useful for tweaking memory settings.
12 | # Default value: -Xmx512m -XX:MaxMetaspaceSize=256m
13 | org.gradle.jvmargs=-Xmx2048m -XX:MaxMetaspaceSize=512m
14 |
15 | # When configured, Gradle will run in incubating parallel mode.
16 | # This option should only be used with decoupled projects. More details, visit
17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
18 | # org.gradle.parallel=true
19 |
20 | # AndroidX package structure to make it clearer which packages are bundled with the
21 | # Android operating system, and which are packaged with your app's APK
22 | # https://developer.android.com/topic/libraries/support-library/androidx-rn
23 | android.useAndroidX=true
24 |
25 | # Enable AAPT2 PNG crunching
26 | android.enablePngCrunchInReleaseBuilds=true
27 |
28 | # Use this property to specify which architecture you want to build.
29 | # You can also override it from the CLI using
30 | # ./gradlew -PreactNativeArchitectures=x86_64
31 | reactNativeArchitectures=armeabi-v7a,arm64-v8a,x86,x86_64
32 |
33 | # Use this property to enable support to the new architecture.
34 | # This will allow you to use TurboModules and the Fabric render in
35 | # your application. You should enable this flag either if you want
36 | # to write custom TurboModules/Fabric components OR use libraries that
37 | # are providing them.
38 | newArchEnabled=false
39 |
40 | # Use this property to enable or disable the Hermes JS engine.
41 | # If set to false, you will be using JSC instead.
42 | hermesEnabled=true
43 |
44 | # Enable GIF support in React Native images (~200 B increase)
45 | expo.gif.enabled=true
46 | # Enable webp support in React Native images (~85 KB increase)
47 | expo.webp.enabled=true
48 | # Enable animated webp support (~3.4 MB increase)
49 | # Disabled by default because iOS doesn't support animated webp
50 | expo.webp.animated=false
51 |
52 | # Enable network inspector
53 | EX_DEV_CLIENT_NETWORK_INSPECTOR=true
54 |
55 | # Use legacy packaging to compress native libraries in the resulting APK.
56 | expo.useLegacyPackaging=false
57 |
--------------------------------------------------------------------------------
/e2e/android/app/src/main/java/com/e2eoktareactnative/MainActivity.kt:
--------------------------------------------------------------------------------
1 | package com.e2eoktareactnative
2 | import expo.modules.splashscreen.SplashScreenManager
3 |
4 | import android.os.Build
5 | import android.os.Bundle
6 |
7 | import com.facebook.react.ReactActivity
8 | import com.facebook.react.ReactActivityDelegate
9 | import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint.fabricEnabled
10 | import com.facebook.react.defaults.DefaultReactActivityDelegate
11 |
12 | import expo.modules.ReactActivityDelegateWrapper
13 |
14 | class MainActivity : ReactActivity() {
15 | override fun onCreate(savedInstanceState: Bundle?) {
16 | // Set the theme to AppTheme BEFORE onCreate to support
17 | // coloring the background, status bar, and navigation bar.
18 | // This is required for expo-splash-screen.
19 | // setTheme(R.style.AppTheme);
20 | // @generated begin expo-splashscreen - expo prebuild (DO NOT MODIFY) sync-f3ff59a738c56c9a6119210cb55f0b613eb8b6af
21 | SplashScreenManager.registerOnActivity(this)
22 | // @generated end expo-splashscreen
23 | super.onCreate(null)
24 | }
25 |
26 | /**
27 | * Returns the name of the main component registered from JavaScript. This is used to schedule
28 | * rendering of the component.
29 | */
30 | override fun getMainComponentName(): String = "main"
31 |
32 | /**
33 | * Returns the instance of the [ReactActivityDelegate]. We use [DefaultReactActivityDelegate]
34 | * which allows you to enable New Architecture with a single boolean flags [fabricEnabled]
35 | */
36 | override fun createReactActivityDelegate(): ReactActivityDelegate {
37 | return ReactActivityDelegateWrapper(
38 | this,
39 | BuildConfig.IS_NEW_ARCHITECTURE_ENABLED,
40 | object : DefaultReactActivityDelegate(
41 | this,
42 | mainComponentName,
43 | fabricEnabled
44 | ){})
45 | }
46 |
47 | /**
48 | * Align the back button behavior with Android S
49 | * where moving root activities to background instead of finishing activities.
50 | * @see onBackPressed
51 | */
52 | override fun invokeDefaultOnBackPressed() {
53 | if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.R) {
54 | if (!moveTaskToBack(false)) {
55 | // For non-root activities, use the default implementation to finish them.
56 | super.invokeDefaultOnBackPressed()
57 | }
58 | return
59 | }
60 |
61 | // Use the default back button implementation on Android S
62 | // because it's doing more than [Activity.moveTaskToBack] in fact.
63 | super.invokeDefaultOnBackPressed()
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/android/src/main/java/com/oktareactnative/OktaSdkConstant.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2019, Okta, Inc. and/or its affiliates. All rights reserved.
3 | * The Okta software accompanied by this notice is provided pursuant to the Apache License, Version 2.0 (the "License.")
4 | *
5 | * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0.
6 | * Unless required by applicable law or agreed to in writing, software
7 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
8 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
9 | *
10 | * See the License for the specific language governing permissions and limitations under the License.
11 | */
12 |
13 |
14 | package com.oktareactnative;
15 |
16 | final class OktaSdkConstant {
17 |
18 | /** ======== Keys ======== **/
19 |
20 | static final String RESOLVE_TYPE_KEY = "resolve_type";
21 |
22 | static final String ACCESS_TOKEN_KEY = "access_token";
23 |
24 | static final String ID_TOKEN_KEY = "id_token";
25 |
26 | static final String REFRESH_TOKEN_KEY = "refresh_token";
27 |
28 | static final String AUTHENTICATED_KEY = "authenticated";
29 |
30 | static final String ERROR_CODE_KEY = "error_code";
31 |
32 | static final String ERROR_MSG_KEY = "error_message";
33 |
34 | static final String ERROR_STACK_TRACE_KEY = "error_stack_trace";
35 |
36 | static final String ACTIVE_KEY = "active";
37 |
38 | static final String TOKEN_TYPE_KEY = "token_type";
39 |
40 | static final String SCOPE_KEY = "scope";
41 |
42 | static final String CLIENT_ID_KEY = "client_id";
43 |
44 | static final String DEVICE_ID_KEY = "device_id";
45 |
46 | static final String USERNAME_KEY = "username";
47 |
48 | static final String NBF_KEY = "nbf";
49 |
50 | static final String EXP_KEY = "exp";
51 |
52 | static final String IAT_KEY = "iat";
53 |
54 | static final String SUB_KEY = "sub";
55 |
56 | static final String AUD_KEY = "aud";
57 |
58 | static final String ISS_KEY = "iss";
59 |
60 | static final String JTI_KEY = "jti";
61 |
62 | static final String UID_KEY = "uid";
63 |
64 | /** ======== Values ======== **/
65 |
66 | static final String AUTHORIZED = "authorized";
67 |
68 | static final String SIGNED_OUT = "signed_out";
69 |
70 | static final String CANCELLED = "cancelled";
71 |
72 | /** ======== Event names ======== **/
73 |
74 | static final String SIGN_IN_SUCCESS = "signInSuccess";
75 |
76 | static final String ON_ERROR = "onError";
77 |
78 | static final String SIGN_OUT_SUCCESS = "signOutSuccess";
79 |
80 | static final String ON_CANCELLED = "onCancelled";
81 |
82 | private OktaSdkConstant() {
83 | throw new AssertionError();
84 | }
85 | }
86 |
--------------------------------------------------------------------------------
/e2e/android/app/src/androidTest/java/com/e2eoktareactnative/customlogin/CustomLoginPage.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023-Present Okta, Inc.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.e2eoktareactnative.customlogin
17 |
18 | import androidx.test.uiautomator.UiSelector
19 | import com.e2eoktareactnative.dashboard.DashboardPage
20 | import com.e2eoktareactnative.test.applyOnViewWithSelector
21 | import com.e2eoktareactnative.test.clickButtonWithText
22 | import com.e2eoktareactnative.test.setTextForIndex
23 | import com.e2eoktareactnative.test.waitForText
24 | import org.hamcrest.CoreMatchers.equalTo
25 | import org.hamcrest.MatcherAssert.assertThat
26 | import kotlin.time.Duration.Companion.seconds
27 |
28 | internal class CustomLoginPage {
29 | init {
30 | waitForText("CustomLogin", timeout = 10L.seconds.inWholeMilliseconds)
31 | }
32 |
33 | fun username(username: String): CustomLoginPage {
34 | setTextForIndex(0, username)
35 | return this
36 | }
37 |
38 | fun password(password: String): CustomLoginPage {
39 | setTextForIndex(1, password)
40 | return this
41 | }
42 |
43 | fun login(): DashboardPage {
44 | clickButtonWithText("SIGN IN")
45 | return DashboardPage()
46 | }
47 |
48 | fun loginExpectingError(): CustomLoginPage {
49 | clickButtonWithText("SIGN IN")
50 | return this
51 | }
52 |
53 | fun assertHasError(error: String): CustomLoginPage {
54 | waitForText(error)
55 | return this
56 | }
57 |
58 | fun pressAlertOkButton(): CustomLoginPage {
59 | applyOnViewWithSelector(UiSelector().text("OK")) { uiObject ->
60 | assertThat(uiObject.waitForExists(10.seconds.inWholeMilliseconds), equalTo(true))
61 | // Checking if clicking "OK" was successful doesn't work on CI device. As an alternative,
62 | // click OK button, and check if the button is no longer visible afterwards
63 | uiObject.click()
64 | assertThat(uiObject.waitForExists(2.seconds.inWholeMilliseconds), equalTo(false))
65 | }
66 | waitForText("CustomLogin", timeout = 10.seconds.inWholeMilliseconds)
67 | return this
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/e2e/ios/E2EOktaReactNative/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CADisableMinimumFrameDurationOnPhone
6 |
7 | CFBundleDevelopmentRegion
8 | $(DEVELOPMENT_LANGUAGE)
9 | CFBundleDisplayName
10 | E2E-Okta-React-Native
11 | CFBundleExecutable
12 | $(EXECUTABLE_NAME)
13 | CFBundleIdentifier
14 | $(PRODUCT_BUNDLE_IDENTIFIER)
15 | CFBundleInfoDictionaryVersion
16 | 6.0
17 | CFBundleName
18 | $(PRODUCT_NAME)
19 | CFBundlePackageType
20 | $(PRODUCT_BUNDLE_PACKAGE_TYPE)
21 | CFBundleShortVersionString
22 | 1.0.0
23 | CFBundleSignature
24 | ????
25 | CFBundleURLTypes
26 |
27 |
28 | CFBundleURLSchemes
29 |
30 | com.e2eoktareactnative
31 |
32 |
33 |
34 | CFBundleVersion
35 | 1
36 | LSRequiresIPhoneOS
37 |
38 | NSAppTransportSecurity
39 |
40 | NSAllowsArbitraryLoads
41 |
42 | NSAllowsLocalNetworking
43 |
44 |
45 | UILaunchStoryboardName
46 | SplashScreen
47 | UIRequiredDeviceCapabilities
48 |
49 | armv64
50 |
51 | UIRequiresFullScreen
52 |
53 | UIStatusBarStyle
54 | UIStatusBarStyleDefault
55 | UISupportedInterfaceOrientations
56 |
57 | UIInterfaceOrientationPortrait
58 | UIInterfaceOrientationPortraitUpsideDown
59 | UIInterfaceOrientationLandscapeLeft
60 | UIInterfaceOrientationLandscapeRight
61 |
62 | UISupportedInterfaceOrientations~ipad
63 |
64 | UIInterfaceOrientationPortrait
65 | UIInterfaceOrientationPortraitUpsideDown
66 | UIInterfaceOrientationLandscapeLeft
67 | UIInterfaceOrientationLandscapeRight
68 |
69 | UIUserInterfaceStyle
70 | Automatic
71 | UIViewControllerBasedStatusBarAppearance
72 |
73 |
74 |
--------------------------------------------------------------------------------
/e2e/ios/Podfile:
--------------------------------------------------------------------------------
1 | require File.join(File.dirname(`node --print "require.resolve('expo/package.json')"`), "scripts/autolinking")
2 | require File.join(File.dirname(`node --print "require.resolve('react-native/package.json')"`), "scripts/react_native_pods")
3 |
4 | require 'json'
5 | podfile_properties = JSON.parse(File.read(File.join(__dir__, 'Podfile.properties.json'))) rescue {}
6 |
7 | ENV['RCT_NEW_ARCH_ENABLED'] = podfile_properties['newArchEnabled'] == 'true' ? '1' : '0'
8 | ENV['EX_DEV_CLIENT_NETWORK_INSPECTOR'] = podfile_properties['EX_DEV_CLIENT_NETWORK_INSPECTOR']
9 |
10 | platform :ios, podfile_properties['ios.deploymentTarget'] || '15.1'
11 | install! 'cocoapods',
12 | :deterministic_uuids => false
13 |
14 | prepare_react_native_project!
15 |
16 | target 'E2EOktaReactNative' do
17 | use_expo_modules!
18 |
19 | if ENV['EXPO_USE_COMMUNITY_AUTOLINKING'] == '1'
20 | config_command = ['node', '-e', "process.argv=['', '', 'config'];require('@react-native-community/cli').run()"];
21 | else
22 | config_command = [
23 | 'node',
24 | '--no-warnings',
25 | '--eval',
26 | 'require(require.resolve(\'expo-modules-autolinking\', { paths: [require.resolve(\'expo/package.json\')] }))(process.argv.slice(1))',
27 | 'react-native-config',
28 | '--json',
29 | '--platform',
30 | 'ios'
31 | ]
32 | end
33 |
34 | config = use_native_modules!(config_command)
35 |
36 | use_frameworks! :linkage => podfile_properties['ios.useFrameworks'].to_sym if podfile_properties['ios.useFrameworks']
37 | use_frameworks! :linkage => ENV['USE_FRAMEWORKS'].to_sym if ENV['USE_FRAMEWORKS']
38 |
39 | use_react_native!(
40 | :path => config[:reactNativePath],
41 | :hermes_enabled => podfile_properties['expo.jsEngine'] == nil || podfile_properties['expo.jsEngine'] == 'hermes',
42 | # An absolute path to your application root.
43 | :app_path => "#{Pod::Config.instance.installation_root}/..",
44 | :privacy_file_aggregation_enabled => podfile_properties['apple.privacyManifestAggregationEnabled'] != 'false',
45 | )
46 |
47 | post_install do |installer|
48 | react_native_post_install(
49 | installer,
50 | config[:reactNativePath],
51 | :mac_catalyst_enabled => false,
52 | :ccache_enabled => podfile_properties['apple.ccacheEnabled'] == 'true',
53 | )
54 |
55 | # This is necessary for Xcode 14, because it signs resource bundles by default
56 | # when building for devices.
57 | installer.target_installation_results.pod_target_installation_results
58 | .each do |pod_name, target_installation_result|
59 | target_installation_result.resource_bundle_targets.each do |resource_bundle_target|
60 | resource_bundle_target.build_configurations.each do |config|
61 | config.build_settings['CODE_SIGNING_ALLOWED'] = 'NO'
62 | end
63 | end
64 | end
65 | end
66 | end
67 |
--------------------------------------------------------------------------------
/ios/Tests/OktaReactNativeErrorTests.swift:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2021-Present, Okta, Inc. and/or its affiliates. All rights reserved.
3 | * The Okta software accompanied by this notice is provided pursuant to the Apache License, Version 2.0 (the "License.")
4 | *
5 | * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0.
6 | * Unless required by applicable law or agreed to in writing, software
7 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
8 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
9 | *
10 | * See the License for the specific language governing permissions and limitations under the License.
11 | */
12 |
13 | import XCTest
14 | @testable import ReactNativeOktaSdkBridge
15 |
16 | final class OktaReactNativeErrorTests: XCTestCase {
17 | func testLocalizedDescription() {
18 | XCTAssertEqual(OktaReactNativeError.notConfigured.localizedDescription, "OktaOidc client isn't configured, check if you have created a configuration with createConfig")
19 | XCTAssertEqual(OktaReactNativeError.noView.localizedDescription, "No current view exists")
20 | XCTAssertEqual(OktaReactNativeError.unauthenticated.localizedDescription, "User is not authenticated, cannot perform the specific action")
21 | XCTAssertEqual(OktaReactNativeError.noStateManager.localizedDescription, "State Manager does not exist.")
22 | XCTAssertEqual(OktaReactNativeError.noIdToken.localizedDescription, "Id token does not exist")
23 | XCTAssertEqual(OktaReactNativeError.oktaOidcError.localizedDescription, "Okta Oidc error")
24 | XCTAssertEqual(OktaReactNativeError.errorTokenType.localizedDescription, "Token type not found")
25 | XCTAssertEqual(OktaReactNativeError.errorPayload.localizedDescription, "Error in retrieving payload")
26 | XCTAssertEqual(OktaReactNativeError.noAccessToken.localizedDescription, "No access token found")
27 | XCTAssertEqual(OktaReactNativeError.cancelled.localizedDescription, "User cancelled a session")
28 | }
29 |
30 | func testErrorCode() {
31 | XCTAssertEqual(OktaReactNativeError.notConfigured.errorCode, "-100")
32 | XCTAssertEqual(OktaReactNativeError.noView.errorCode, "-200")
33 | XCTAssertEqual(OktaReactNativeError.unauthenticated.errorCode, "-300")
34 | XCTAssertEqual(OktaReactNativeError.noStateManager.errorCode, "-400")
35 | XCTAssertEqual(OktaReactNativeError.noIdToken.errorCode, "-500")
36 | XCTAssertEqual(OktaReactNativeError.oktaOidcError.errorCode, "-600")
37 | XCTAssertEqual(OktaReactNativeError.errorTokenType.errorCode, "-700")
38 | XCTAssertEqual(OktaReactNativeError.errorPayload.errorCode, "-800")
39 | XCTAssertEqual(OktaReactNativeError.noAccessToken.errorCode, "-900")
40 | XCTAssertEqual(OktaReactNativeError.cancelled.errorCode, "-1200")
41 | }
42 |
43 | }
44 |
--------------------------------------------------------------------------------
/.eslintrc.js:
--------------------------------------------------------------------------------
1 | // https://eslint.org/docs/user-guide/configuring
2 |
3 | module.exports = {
4 | ignorePatterns: ['node_modules/', 'dist/', 'e2e'],
5 | extends: [
6 | 'eslint:recommended',
7 | 'plugin:node/recommended-script',
8 | 'plugin:jest/recommended',
9 | ],
10 | rules: {
11 | 'semi': ['error', 'always'],
12 | 'indent': ['error', 2],
13 | 'no-var': 0,
14 | 'prefer-rest-params': 0,
15 | 'prefer-spread': 0,
16 | 'prefer-const': 0,
17 | 'node/no-unpublished-require': 0,
18 | 'node/no-unpublished-import': 0,
19 | 'camelcase': 2,
20 | 'complexity': [2, 7],
21 | 'curly': 2,
22 | 'dot-notation': 0,
23 | 'guard-for-in': 2,
24 | 'new-cap': [2, { 'properties': false }],
25 | 'no-caller': 2,
26 | 'no-empty': 2,
27 | 'no-eval': 2,
28 | 'no-implied-eval': 2,
29 | 'no-multi-str': 0,
30 | 'no-new': 2,
31 | 'no-plusplus': 0,
32 | 'no-undef': 2,
33 | 'no-unused-expressions': [2, { 'allowShortCircuit': true, 'allowTernary': true }],
34 | 'no-unused-vars': 2,
35 | 'max-depth': [2, 3],
36 | 'max-len': [2, 150],
37 | 'max-params': [2, 5],
38 | 'max-statements': [2, 25],
39 | 'quotes': [2, 'single', { 'allowTemplateLiterals': true }],
40 | 'strict': 0,
41 | 'wrap-iife': [2, 'any'],
42 | },
43 | overrides: [
44 | {
45 | files: ['*.ts', '*.tsx'],
46 | extends: [
47 | 'plugin:@typescript-eslint/eslint-recommended',
48 | 'plugin:@typescript-eslint/recommended'
49 | ],
50 | parser: '@typescript-eslint/parser',
51 | parserOptions: {
52 | ecmaVersion: 2020,
53 | ecmaFeatures: { 'jsx': true },
54 | sourceType: 'module',
55 | project: 'types/tsconfig.json'
56 | },
57 | env: {
58 | es6: true,
59 | node: false
60 | },
61 | plugins: ['@typescript-eslint'],
62 | rules: {
63 | 'node/no-unsupported-features/es-syntax': 0,
64 | 'node/no-unsupported-features/node-builtins': 0
65 | }
66 | },
67 | {
68 | // ES6 processed by Babel
69 | files: [
70 | '*.js',
71 | '*.test.js'
72 | ],
73 | plugins: [
74 | 'node',
75 | 'jest',
76 | ],
77 | parser: '@babel/eslint-parser',
78 | parserOptions: {
79 | ecmaVersion: 2020,
80 | sourceType: 'module'
81 | },
82 | env: {
83 | es6: true,
84 | node: false
85 | },
86 | rules: {
87 | 'node/no-unsupported-features/es-syntax': 0,
88 | 'node/no-unsupported-features/node-builtins': 0
89 | }
90 | },
91 | {
92 | // Jest specs
93 | files: ['*.test.js'],
94 | plugins: [
95 | 'node',
96 | 'jest',
97 | ],
98 | env: {
99 | jest: true
100 | }
101 | }
102 | ]
103 | };
104 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing to Okta Open Source Repos
2 |
3 | Thank you for your interest in contributing to Okta's Open Source Projects! Before submitting a PR, please take a moment to read over our [Contributer License Agreement](https://developer.okta.com/cla/). In certain cases, we ask that you [sign a CLA](https://developer.okta.com/sites/all/themes/developer/pdf/okta_individual_contributor_license_agreement_2016-11.pdf) before we merge your pull request.
4 |
5 | - [Commit Message Guidelines](#commit-message-guidelines)
6 | * [Git Commit Messages](#git-commit-messages)
7 | * [Template](#template)
8 | * [Template for specific package change](#template-for-specific-package-change)
9 | * [Type](#type)
10 | * [Example](#example)
11 | * [Example for specific package change](#example-for-specific-package-change)
12 | * [Breaking changes](#breaking-changes)
13 | * [Example for a breaking change](#example-for-a-breaking-change)
14 |
15 | ## Commit Message Guidelines
16 |
17 | ### Git Commit Messages
18 |
19 | We use an adapted form of [Conventional Commits](http://conventionalcommits.org/).
20 |
21 | * Use the present tense ("Adds feature" not "Added feature")
22 | * Limit the first line to 72 characters or less
23 | * Add one feature per commit. If you have multiple features, have multiple commits.
24 |
25 | ### Template
26 |
27 | : Short Description of Commit
28 |
29 | More detailed description of commit
30 |
31 | (Optional) Resolves:
32 |
33 | ### Template for specific package change
34 |
35 | []: Short Description of Commit
36 |
37 | More detailed description of commit
38 |
39 | (Optional) Resolves:
40 |
41 | ### Type
42 | Our types include:
43 | * `feat` when creating a new feature
44 | * `fix` when fixing a bug
45 | * `test` when adding tests
46 | * `refactor` when improving the format/structure of the code
47 | * `docs` when writing docs
48 | * `release` when pushing a new release
49 | * `chore` others (ex: upgrading/downgrading dependencies)
50 |
51 |
52 | ### Example
53 |
54 | docs: Updates CONTRIBUTING.md
55 |
56 | Updates Contributing.md with new emoji categories
57 | Updates Contributing.md with new template
58 |
59 | Resolves: #1234
60 |
61 | ### Example for specific package change
62 | fix[okta-angular]: Fixes bad bug
63 |
64 | Fixes a very bad bug in okta-angular
65 |
66 | Resolves: #5678
67 |
68 | ### Breaking changes
69 |
70 | * Breaking changes MUST be indicated at the very beginning of the body section of a commit. A breaking change MUST consist of the uppercase text `BREAKING CHANGE`, followed by a colon and a space.
71 | * A description MUST be provided after the `BREAKING CHANGE:`, describing what has changed about the API.
72 |
73 | ### Example for a breaking change
74 |
75 | feat: Allows provided config object to extend other configs
76 |
77 | BREAKING CHANGE: `extends` key in config file is now used for extending other config files
78 |
--------------------------------------------------------------------------------
/ios/OktaSdkBridge/OktaSDKError.swift:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2019-Present, Okta, Inc. and/or its affiliates. All rights reserved.
3 | * The Okta software accompanied by this notice is provided pursuant to the Apache License, Version 2.0 (the "License.")
4 | *
5 | * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0.
6 | * Unless required by applicable law or agreed to in writing, software
7 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
8 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
9 | *
10 | * See the License for the specific language governing permissions and limitations under the License.
11 | */
12 |
13 | import Foundation
14 |
15 | public enum OktaReactNativeError: Error {
16 | case notConfigured
17 | case noView
18 | case unauthenticated
19 | case noStateManager
20 | case noIdToken
21 | case oktaOidcError
22 | case errorTokenType
23 | case errorPayload
24 | case noAccessToken
25 | case cancelled
26 | }
27 |
28 | extension OktaReactNativeError: LocalizedError {
29 | public var errorDescription: String? {
30 | switch self {
31 | case .notConfigured:
32 | return NSLocalizedString("OktaOidc client isn't configured, check if you have created a configuration with createConfig", comment: "")
33 | case .noView:
34 | return NSLocalizedString("No current view exists", comment: "")
35 | case .unauthenticated:
36 | return NSLocalizedString("User is not authenticated, cannot perform the specific action", comment: "")
37 | case .noStateManager:
38 | return NSLocalizedString("State Manager does not exist.", comment: "")
39 | case .noIdToken:
40 | return NSLocalizedString("Id token does not exist", comment: "")
41 | case .oktaOidcError:
42 | return NSLocalizedString("Okta Oidc error", comment: "")
43 | case .errorTokenType:
44 | return NSLocalizedString("Token type not found", comment: "")
45 | case .errorPayload:
46 | return NSLocalizedString("Error in retrieving payload", comment: "")
47 | case .noAccessToken:
48 | return NSLocalizedString("No access token found", comment: "")
49 | case .cancelled:
50 | return NSLocalizedString("User cancelled a session", comment: "")
51 | }
52 | }
53 | public var errorCode: String? {
54 | switch self {
55 | case .notConfigured:
56 | return "-100"
57 | case .noView:
58 | return "-200"
59 | case .unauthenticated:
60 | return "-300"
61 | case .noStateManager:
62 | return "-400"
63 | case .noIdToken:
64 | return "-500"
65 | case .oktaOidcError:
66 | return "-600"
67 | case .errorTokenType:
68 | return "-700"
69 | case .errorPayload:
70 | return "-800"
71 | case .noAccessToken:
72 | return "-900"
73 | case .cancelled:
74 | return "-1200"
75 | }
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/android/gradlew.bat:
--------------------------------------------------------------------------------
1 | @rem
2 | @rem Copyright 2015 the original author or authors.
3 | @rem
4 | @rem Licensed under the Apache License, Version 2.0 (the "License");
5 | @rem you may not use this file except in compliance with the License.
6 | @rem You may obtain a copy of the License at
7 | @rem
8 | @rem https://www.apache.org/licenses/LICENSE-2.0
9 | @rem
10 | @rem Unless required by applicable law or agreed to in writing, software
11 | @rem distributed under the License is distributed on an "AS IS" BASIS,
12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | @rem See the License for the specific language governing permissions and
14 | @rem limitations under the License.
15 | @rem
16 |
17 | @if "%DEBUG%"=="" @echo off
18 | @rem ##########################################################################
19 | @rem
20 | @rem Gradle startup script for Windows
21 | @rem
22 | @rem ##########################################################################
23 |
24 | @rem Set local scope for the variables with windows NT shell
25 | if "%OS%"=="Windows_NT" setlocal
26 |
27 | set DIRNAME=%~dp0
28 | if "%DIRNAME%"=="" set DIRNAME=.
29 | @rem This is normally unused
30 | set APP_BASE_NAME=%~n0
31 | set APP_HOME=%DIRNAME%
32 |
33 | @rem Resolve any "." and ".." in APP_HOME to make it shorter.
34 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
35 |
36 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
37 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
38 |
39 | @rem Find java.exe
40 | if defined JAVA_HOME goto findJavaFromJavaHome
41 |
42 | set JAVA_EXE=java.exe
43 | %JAVA_EXE% -version >NUL 2>&1
44 | if %ERRORLEVEL% equ 0 goto execute
45 |
46 | echo. 1>&2
47 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
48 | echo. 1>&2
49 | echo Please set the JAVA_HOME variable in your environment to match the 1>&2
50 | echo location of your Java installation. 1>&2
51 |
52 | goto fail
53 |
54 | :findJavaFromJavaHome
55 | set JAVA_HOME=%JAVA_HOME:"=%
56 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
57 |
58 | if exist "%JAVA_EXE%" goto execute
59 |
60 | echo. 1>&2
61 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
62 | echo. 1>&2
63 | echo Please set the JAVA_HOME variable in your environment to match the 1>&2
64 | echo location of your Java installation. 1>&2
65 |
66 | goto fail
67 |
68 | :execute
69 | @rem Setup the command line
70 |
71 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
72 |
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if %ERRORLEVEL% equ 0 goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | set EXIT_CODE=%ERRORLEVEL%
85 | if %EXIT_CODE% equ 0 set EXIT_CODE=1
86 | if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
87 | exit /b %EXIT_CODE%
88 |
89 | :mainEnd
90 | if "%OS%"=="Windows_NT" endlocal
91 |
92 | :omega
93 |
--------------------------------------------------------------------------------
/e2e/android/gradlew.bat:
--------------------------------------------------------------------------------
1 | @rem
2 | @rem Copyright 2015 the original author or authors.
3 | @rem
4 | @rem Licensed under the Apache License, Version 2.0 (the "License");
5 | @rem you may not use this file except in compliance with the License.
6 | @rem You may obtain a copy of the License at
7 | @rem
8 | @rem https://www.apache.org/licenses/LICENSE-2.0
9 | @rem
10 | @rem Unless required by applicable law or agreed to in writing, software
11 | @rem distributed under the License is distributed on an "AS IS" BASIS,
12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | @rem See the License for the specific language governing permissions and
14 | @rem limitations under the License.
15 | @rem
16 | @rem SPDX-License-Identifier: Apache-2.0
17 | @rem
18 |
19 | @if "%DEBUG%"=="" @echo off
20 | @rem ##########################################################################
21 | @rem
22 | @rem Gradle startup script for Windows
23 | @rem
24 | @rem ##########################################################################
25 |
26 | @rem Set local scope for the variables with windows NT shell
27 | if "%OS%"=="Windows_NT" setlocal
28 |
29 | set DIRNAME=%~dp0
30 | if "%DIRNAME%"=="" set DIRNAME=.
31 | @rem This is normally unused
32 | set APP_BASE_NAME=%~n0
33 | set APP_HOME=%DIRNAME%
34 |
35 | @rem Resolve any "." and ".." in APP_HOME to make it shorter.
36 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
37 |
38 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
39 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
40 |
41 | @rem Find java.exe
42 | if defined JAVA_HOME goto findJavaFromJavaHome
43 |
44 | set JAVA_EXE=java.exe
45 | %JAVA_EXE% -version >NUL 2>&1
46 | if %ERRORLEVEL% equ 0 goto execute
47 |
48 | echo. 1>&2
49 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
50 | echo. 1>&2
51 | echo Please set the JAVA_HOME variable in your environment to match the 1>&2
52 | echo location of your Java installation. 1>&2
53 |
54 | goto fail
55 |
56 | :findJavaFromJavaHome
57 | set JAVA_HOME=%JAVA_HOME:"=%
58 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
59 |
60 | if exist "%JAVA_EXE%" goto execute
61 |
62 | echo. 1>&2
63 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
64 | echo. 1>&2
65 | echo Please set the JAVA_HOME variable in your environment to match the 1>&2
66 | echo location of your Java installation. 1>&2
67 |
68 | goto fail
69 |
70 | :execute
71 | @rem Setup the command line
72 |
73 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
74 |
75 |
76 | @rem Execute Gradle
77 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
78 |
79 | :end
80 | @rem End local scope for the variables with windows NT shell
81 | if %ERRORLEVEL% equ 0 goto mainEnd
82 |
83 | :fail
84 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
85 | rem the _cmd.exe /c_ return code!
86 | set EXIT_CODE=%ERRORLEVEL%
87 | if %EXIT_CODE% equ 0 set EXIT_CODE=1
88 | if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
89 | exit /b %EXIT_CODE%
90 |
91 | :mainEnd
92 | if "%OS%"=="Windows_NT" endlocal
93 |
94 | :omega
95 |
--------------------------------------------------------------------------------
/types/index.test-d.ts:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2021-Present, Okta, Inc. and/or its affiliates. All rights reserved.
3 | * The Okta software accompanied by this notice is provided pursuant to the Apache License, Version 2.0 (the "License.")
4 | *
5 | * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0.
6 | * Unless required by applicable law or agreed to in writing, software
7 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
8 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
9 | *
10 | * See the License for the specific language governing permissions and limitations under the License.
11 | */
12 |
13 |
14 | /* eslint-disable node/no-missing-import, camelcase */
15 | import OktaSDK, { Okta } from './index';
16 | import { expectType } from 'tsd';
17 | import { OktaAuth } from '@okta/okta-auth-js';
18 |
19 | expectType>(OktaSDK.createConfig({
20 | issuer: '{issuer}',
21 | clientId: '{clientID}',
22 | redirectUri: '{redirectUri}',
23 | endSessionRedirectUri: '{endSessionRedirectUri}',
24 | discoveryUri: '{discoveryUri}',
25 | scopes: ['scope1', 'scope2'],
26 | requireHardwareBackedKeyStore: false,
27 | androidChromeTabColor: '#00000',
28 | httpConnectionTimeout: 15,
29 | httpReadTimeout: 10,
30 | browserMatchAll: false,
31 | oktaAuthConfig: { issuer: '{issuer}' }
32 | }));
33 |
34 | expectType(OktaSDK.getAuthClient());
35 |
36 | expectType>(OktaSDK.signIn());
37 |
38 | expectType>(OktaSDK.signIn({ username: '{username}', password: '{password}' }));
39 |
40 | expectType>(OktaSDK.signInWithBrowser());
41 |
42 | expectType>(OktaSDK.signInWithBrowser({ idp: '{idp}' }));
43 |
44 | expectType>(OktaSDK.signInWithBrowser({ noSSO: true }));
45 |
46 | expectType>(OktaSDK.signInWithBrowser({ login_hint: 'some@email.com' }));
47 |
48 | expectType>(OktaSDK.signInWithBrowser({ prompt: 'Prompt' }));
49 |
50 | expectType>(OktaSDK.authenticate({ sessionToken: 'sessionToken' }));
51 |
52 | expectType>(OktaSDK.signOut());
53 |
54 | expectType>(OktaSDK.getIdToken());
55 |
56 | expectType>(OktaSDK.getAccessToken());
57 |
58 | expectType>(OktaSDK.getUser());
59 |
60 | expectType>(OktaSDK.getUserFromIdToken());
61 |
62 | expectType>(OktaSDK.isAuthenticated());
63 |
64 | expectType>(OktaSDK.revokeAccessToken());
65 |
66 | expectType>(OktaSDK.revokeIdToken());
67 |
68 | expectType>(OktaSDK.revokeRefreshToken());
69 |
70 | expectType>(OktaSDK.introspectAccessToken());
71 |
72 | expectType>(OktaSDK.introspectIdToken());
73 |
74 | expectType>(OktaSDK.introspectRefreshToken());
75 |
76 | expectType>(OktaSDK.refreshTokens());
77 |
78 | expectType>(OktaSDK.clearTokens());
79 |
--------------------------------------------------------------------------------
/e2e/android/app/src/androidTest/java/com/e2eoktareactnative/test/UiAutomationHelpers.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023-Present Okta, Inc.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.e2eoktareactnative.test
17 |
18 | import android.widget.EditText
19 | import androidx.test.platform.app.InstrumentationRegistry
20 | import androidx.test.uiautomator.UiDevice
21 | import androidx.test.uiautomator.UiObject
22 | import androidx.test.uiautomator.UiSelector
23 | import org.hamcrest.CoreMatchers.equalTo
24 | import org.hamcrest.MatcherAssert.assertThat
25 | import kotlin.time.Duration.Companion.seconds
26 |
27 | fun clickButtonWithText(text: String, timeout: Long? = null) {
28 | clickButtonWithSelector(UiSelector().text(text), timeout)
29 | }
30 |
31 | fun clickButtonWithTextMatching(text: String, timeout: Long? = null) {
32 | clickButtonWithSelector(UiSelector().textMatches(text), timeout)
33 | }
34 |
35 | fun clickButtonWithSelector(selector: UiSelector, timeout: Long? = null) {
36 | applyOnViewWithSelector(selector) { uiObject ->
37 | timeout?.let {
38 | assertThat(uiObject.waitForExists(timeout), equalTo(true))
39 | }
40 | assertThat(uiObject.click(), equalTo(true))
41 | }
42 | }
43 |
44 | fun setTextForIndex(index: Int, text: String) {
45 | val uiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
46 | val selector = UiSelector().className(EditText::class.java).instance(index)
47 | assertThat(uiDevice.findObject(selector).setText(text), equalTo(true))
48 | }
49 |
50 | fun waitForText(text: String, timeout: Long = 10.seconds.inWholeMilliseconds) {
51 | waitForViewWithSelector(UiSelector().text(text), timeout)
52 | }
53 |
54 | fun waitForTextMatching(text: String, timeout: Long = 10.seconds.inWholeMilliseconds) {
55 | waitForViewWithSelector(UiSelector().textMatches(text), timeout)
56 | }
57 |
58 | fun waitForResourceIdWithText(resourceId: String, text: String, timeout: Long = 10.seconds.inWholeMilliseconds) {
59 | waitForViewWithSelector(UiSelector().resourceIdMatches(resourceId).text(text), timeout)
60 | }
61 |
62 | fun waitForResourceId(resourceId: String, timeout: Long = 10.seconds.inWholeMilliseconds) {
63 | waitForViewWithSelector(UiSelector().resourceIdMatches(resourceId), timeout)
64 | }
65 |
66 | fun waitForViewWithSelector(selector: UiSelector, timeout: Long = 10.seconds.inWholeMilliseconds) {
67 | applyOnViewWithSelector(selector) { uiObject ->
68 | assertThat(uiObject.waitForExists(timeout), equalTo(true))
69 | }
70 | }
71 |
72 | fun applyOnViewWithSelector(selector: UiSelector, uiObjectFunction: (UiObject) -> Unit) {
73 | val uiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
74 | uiObjectFunction(uiDevice.findObject(selector))
75 | }
76 |
--------------------------------------------------------------------------------
/e2e/pages/ProfilePage.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2021-Present, Okta, Inc. and/or its affiliates. All rights reserved.
3 | * The Okta software accompanied by this notice is provided pursuant to the Apache License, Version 2.0 (the "License.")
4 | *
5 | * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0.
6 | * Unless required by applicable law or agreed to in writing, software
7 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
8 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
9 | *
10 | * See the License for the specific language governing permissions and limitations under the License.
11 | */
12 |
13 | /* eslint-disable no-unused-vars */
14 | /* eslint-disable node/no-missing-import */
15 |
16 | import React from 'react';
17 | import {
18 | Text,
19 | Button,
20 | StyleSheet,
21 | TextInput,
22 | View,
23 | } from 'react-native';
24 |
25 | import {
26 | signOut,
27 | revokeAccessToken,
28 | revokeIdToken,
29 | clearTokens,
30 | getAccessToken,
31 | getAuthClient,
32 | } from '@okta/okta-react-native';
33 |
34 | export default class ProfilePage extends React.Component {
35 | constructor(props) {
36 | super(props);
37 |
38 | this.state = {
39 | idToken: props.route.params.idToken,
40 | isBrowserScenario: props.route.params.isBrowserScenario,
41 | userInfo: {}
42 | };
43 | }
44 |
45 | async getUserInfo() {
46 | const oktaAuth = getAuthClient();
47 | const issuer = oktaAuth.options.issuer;
48 | const baseUrl = issuer.indexOf('/oauth2') > 0 ? issuer : issuer + '/oauth2';
49 | const accessToken = await getAccessToken();
50 | const url = baseUrl + '/v1/userinfo';
51 | const headers = {
52 | 'Authorization': 'Bearer ' + accessToken.access_token
53 | };
54 | const resp = await fetch(url, {
55 | method: 'GET',
56 | headers,
57 | });
58 | const userInfo = await resp.json();
59 | this.setState({
60 | ...this.state,
61 | userInfo,
62 | });
63 | }
64 |
65 | componentDidMount() {
66 | this.getUserInfo();
67 | }
68 |
69 | logout = () => {
70 | if (this.state.isBrowserScenario == true) {
71 | signOut().then(() => {
72 | this.props.navigation.popToTop();
73 | }).catch(error => {
74 | console.log(error);
75 | });
76 | }
77 |
78 | Promise.all([revokeAccessToken(), clearTokens()])
79 | .then(() => {
80 | this.props.navigation.popToTop();
81 | }).catch(error => {
82 | console.log(error);
83 | });
84 | }
85 |
86 | render() {
87 | const userName = this.state.userInfo.name;
88 | const preferredUserName = this.state.userInfo.preferred_username;
89 | return (
90 |
91 | {userName && User: {userName}}
92 | Welcome back, {preferredUserName}!
93 |
98 |
99 | );
100 | }
101 | }
102 |
103 | const styles = StyleSheet.create({
104 | container: {
105 | flex: 1,
106 | backgroundColor: '#fff',
107 | alignItems: 'center',
108 | justifyContent: 'center',
109 | },
110 | });
--------------------------------------------------------------------------------
/ios/OktaSdkBridge/ReactNativeOktaSdkBridge.m:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2019-Present, Okta, Inc. and/or its affiliates. All rights reserved.
3 | * The Okta software accompanied by this notice is provided pursuant to the Apache License, Version 2.0 (the "License.")
4 | *
5 | * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0.
6 | * Unless required by applicable law or agreed to in writing, software
7 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
8 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
9 | *
10 | * See the License for the specific language governing permissions and limitations under the License.
11 | */
12 |
13 | #import "ReactNativeOktaSdkBridge-Bridging-Header.h"
14 |
15 | @interface RCT_EXTERN_MODULE(OktaSdkBridge, RCTEventEmitter)
16 |
17 | RCT_EXTERN_METHOD(
18 | createConfig:
19 | (NSString *)clientId
20 | redirectUrl:(NSString *)redirectUrl
21 | endSessionRedirectUri:(NSString *)endSessionRedirectUri
22 | discoveryUri:(NSString *)discoveryUri
23 | scopes:(NSString *)scopes
24 | userAgentTemplate:(NSString *)userAgentTemplate
25 | requestTimeout:(NSInteger)requestTimeout
26 | successCallback:(RCTResponseSenderBlock *)successCallback
27 | errorCallback:(RCTResponseSenderBlock *)errorCallback
28 | )
29 |
30 | RCT_EXTERN_METHOD(
31 | signIn:(NSDictionary*)options
32 | promiseResolver:(RCTPromiseResolveBlock *)promiseResolver
33 | promiseRejecter:(RCTPromiseRejectBlock *)promiseRejecter
34 | )
35 |
36 | RCT_EXTERN_METHOD(
37 | authenticate:
38 | (NSString *)sessionToken
39 | promiseResolver:(RCTPromiseResolveBlock *)promiseResolver
40 | promiseRejecter:(RCTPromiseRejectBlock *)promiseRejecter
41 | )
42 |
43 | RCT_EXTERN_METHOD(signOut:(RCTPromiseResolveBlock *)promiseResolver
44 | promiseRejecter:(RCTPromiseRejectBlock *)promiseRejecter)
45 |
46 | RCT_EXTERN_METHOD(getAccessToken:(RCTPromiseResolveBlock *)promiseResolver promiseRejecter:(RCTPromiseRejectBlock *)promiseRejecter)
47 |
48 | RCT_EXTERN_METHOD(getIdToken:(RCTPromiseResolveBlock *)promiseResolver promiseRejecter:(RCTPromiseRejectBlock *)promiseRejecter)
49 |
50 | RCT_EXTERN_METHOD(getUser:(RCTPromiseResolveBlock *)promiseResolver promiseRejecter:(RCTPromiseRejectBlock *)promiseRejecter)
51 |
52 | RCT_EXTERN_METHOD(isAuthenticated:(RCTPromiseResolveBlock *)promiseResolver promiseRejecter:(RCTPromiseRejectBlock *)promiseRejecter)
53 |
54 | RCT_EXTERN_METHOD(revokeAccessToken:(RCTPromiseResolveBlock *)promiseResolver promiseRejecter:(RCTPromiseRejectBlock *)promiseRejecter)
55 |
56 | RCT_EXTERN_METHOD(revokeIdToken:(RCTPromiseResolveBlock *)promiseResolver promiseRejecter:(RCTPromiseRejectBlock *)promiseRejecter)
57 |
58 | RCT_EXTERN_METHOD(revokeRefreshToken:(RCTPromiseResolveBlock *)promiseResolver promiseRejecter:(RCTPromiseRejectBlock *)promiseRejecter)
59 |
60 | RCT_EXTERN_METHOD(introspectAccessToken:(RCTPromiseResolveBlock *)promiseResolver promiseRejecter:(RCTPromiseRejectBlock *)promiseRejecter)
61 |
62 | RCT_EXTERN_METHOD(introspectIdToken:(RCTPromiseResolveBlock *)promiseResolver promiseRejecter:(RCTPromiseRejectBlock *)promiseRejecter)
63 |
64 | RCT_EXTERN_METHOD(introspectRefreshToken:(RCTPromiseResolveBlock *)promiseResolver promiseRejecter:(RCTPromiseRejectBlock *)promiseRejecter)
65 |
66 | RCT_EXTERN_METHOD(refreshTokens:(RCTPromiseResolveBlock *)promiseResolver promiseRejecter:(RCTPromiseRejectBlock *)promiseRejecter)
67 |
68 | RCT_EXTERN_METHOD(clearTokens:(RCTPromiseResolveBlock *)promiseResolver promiseRejecter:(RCTPromiseRejectBlock *)promiseRejecter)
69 |
70 | @end
71 |
--------------------------------------------------------------------------------
/e2e/ios/E2EOktaReactNative/AppDelegate.mm:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2021-Present, Okta, Inc. and/or its affiliates. All rights reserved.
3 | * The Okta software accompanied by this notice is provided pursuant to the Apache License, Version 2.0 (the "License.")
4 | *
5 | * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0.
6 | * Unless required by applicable law or agreed to in writing, software
7 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
8 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
9 | *
10 | * See the License for the specific language governing permissions and limitations under the License.
11 | */
12 |
13 | #import "AppDelegate.h"
14 |
15 | #import
16 | #import
17 |
18 | @implementation AppDelegate
19 |
20 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
21 | {
22 | self.moduleName = @"main";
23 |
24 | // You can add your custom initial props in the dictionary below.
25 | // They will be passed down to the ViewController used by React Native.
26 | self.initialProps = @{};
27 |
28 | return [super application:application didFinishLaunchingWithOptions:launchOptions];
29 | }
30 |
31 | - (NSURL *)sourceURLForBridge:(RCTBridge *)bridge
32 | {
33 | return [self bundleURL];
34 | }
35 |
36 | - (NSURL *)bundleURL
37 | {
38 | #if DEBUG
39 | return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@".expo/.virtual-metro-entry"];
40 | #else
41 | return [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"];
42 | #endif
43 | }
44 |
45 | // Linking API
46 | - (BOOL)application:(UIApplication *)application openURL:(NSURL *)url options:(NSDictionary *)options {
47 | return [super application:application openURL:url options:options] || [RCTLinkingManager application:application openURL:url options:options];
48 | }
49 |
50 | // Universal Links
51 | - (BOOL)application:(UIApplication *)application continueUserActivity:(nonnull NSUserActivity *)userActivity restorationHandler:(nonnull void (^)(NSArray> * _Nullable))restorationHandler {
52 | BOOL result = [RCTLinkingManager application:application continueUserActivity:userActivity restorationHandler:restorationHandler];
53 | return [super application:application continueUserActivity:userActivity restorationHandler:restorationHandler] || result;
54 | }
55 |
56 | // Explicitly define remote notification delegates to ensure compatibility with some third-party libraries
57 | - (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken
58 | {
59 | return [super application:application didRegisterForRemoteNotificationsWithDeviceToken:deviceToken];
60 | }
61 |
62 | // Explicitly define remote notification delegates to ensure compatibility with some third-party libraries
63 | - (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error
64 | {
65 | return [super application:application didFailToRegisterForRemoteNotificationsWithError:error];
66 | }
67 |
68 | // Explicitly define remote notification delegates to ensure compatibility with some third-party libraries
69 | - (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler
70 | {
71 | return [super application:application didReceiveRemoteNotification:userInfo fetchCompletionHandler:completionHandler];
72 | }
73 |
74 | @end
75 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "private": true,
3 | "name": "@okta/okta-react-native",
4 | "title": "React Native Okta Sdk Bridge",
5 | "version": "2.18.0",
6 | "types": "types/index.d.ts",
7 | "description": "Okta OIDC for React Native",
8 | "main": "dist/index.js",
9 | "podname": "OktaSdkBridgeReactNative",
10 | "homepage": "https://github.com/okta/okta-react-native",
11 | "scripts": {
12 | "build": "node ./scripts/build.js",
13 | "lint": "eslint .",
14 | "lint:report": "eslint -f checkstyle -o ./test-reports/lint/eslint-checkstyle-result.xml .",
15 | "prepare": "yarn build",
16 | "test": "jest && tsd",
17 | "tsd": "tsd",
18 | "test:debug": "node --inspect-brk node_modules/jest/bin/jest.js --runInBand"
19 | },
20 | "repository": {
21 | "type": "git",
22 | "url": "git+https://github.com/okta/okta-react-native.git"
23 | },
24 | "files": [
25 | "index.js",
26 | "types/index.d.ts",
27 | "android",
28 | "ios",
29 | "LICENSE",
30 | "CHANGELOG.md",
31 | "package.json",
32 | "OktaSdkBridgeReactNative.podspec"
33 | ],
34 | "keywords": [
35 | "react",
36 | "react-native",
37 | "authentication",
38 | "okta",
39 | "oidc"
40 | ],
41 | "author": "developer@okta.com",
42 | "license": "Apache-2.0",
43 | "readmeFilename": "README.md",
44 | "peerDependencies": {
45 | "events": "^3.1.0",
46 | "react": "^16.13.0 || ^17.0.0 || ^18.0.0",
47 | "react-native": ">=0.70.1"
48 | },
49 | "devDependencies": {
50 | "@babel/core": "^7.18.9",
51 | "@babel/eslint-parser": "^7.17.0",
52 | "@babel/preset-env": "^7.17.10",
53 | "@babel/runtime": "^7.17.9",
54 | "@react-native-community/eslint-config": "^3.2.0",
55 | "@types/jest": "^29.5.12",
56 | "@types/react": "^18.0.9",
57 | "@types/react-test-renderer": "^18.0.0",
58 | "@typescript-eslint/eslint-plugin": "^7.11.0",
59 | "@typescript-eslint/parser": "^7.11.0",
60 | "babel-jest": "^29.7.0",
61 | "chalk": "^4.1.2",
62 | "eslint": "^8.5.6",
63 | "eslint-plugin-jest": "^28.5.0",
64 | "eslint-plugin-node": "^11.1.0",
65 | "jest": "^29.7.0",
66 | "jest-junit": "^16.0.0",
67 | "metro-react-native-babel-preset": "^0.76.3",
68 | "react": "18.2.0",
69 | "react-native": "~0.73.0",
70 | "shelljs": "^0.8.5",
71 | "tsd": "^0.31.0",
72 | "typescript": "^5.4.5"
73 | },
74 | "dependencies": {
75 | "@babel/plugin-transform-async-to-generator": "^7.24.7",
76 | "@okta/okta-auth-js": "7.8.1",
77 | "jscodeshift": "^0.15.2",
78 | "jwt-decode": "^4.0.0",
79 | "url-parse": "^1.5.10",
80 | "ws": "^8.18.0"
81 | },
82 | "resolutions": {
83 | "jscodeshift": "^0.15.2",
84 | "glob": "^9.3.5",
85 | "tar": "^6.2.1",
86 | "micromatch": "^4.0.7",
87 | "braces": "^3.0.3",
88 | "ws": "^8.18.0"
89 | },
90 | "jest": {
91 | "coverageDirectory": "/test-reports/coverage",
92 | "collectCoverage": true,
93 | "collectCoverageFrom": [
94 | "**/*.js",
95 | "!**/*.test.js"
96 | ],
97 | "reporters": [
98 | "default",
99 | "jest-junit"
100 | ],
101 | "roots": [
102 | "./"
103 | ],
104 | "restoreMocks": true,
105 | "automock": false,
106 | "preset": "./scripts/build.js",
107 | "setupFiles": [
108 | "./setupJest.js"
109 | ]
110 | },
111 | "jest-junit": {
112 | "outputDirectory": "./test-reports/unit/",
113 | "outputName": "junit-result.xml"
114 | },
115 | "tsd": {
116 | "directory": "./dist/types"
117 | }
118 | }
119 |
--------------------------------------------------------------------------------
/types/index.d.ts:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2021-Present, Okta, Inc. and/or its affiliates. All rights reserved.
3 | * The Okta software accompanied by this notice is provided pursuant to the Apache License, Version 2.0 (the "License.")
4 | *
5 | * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0.
6 | * Unless required by applicable law or agreed to in writing, software
7 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
8 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
9 | *
10 | * See the License for the specific language governing permissions and limitations under the License.
11 | */
12 |
13 | // TypeScript Version: 4.1
14 |
15 | /* eslint-disable @typescript-eslint/no-unused-vars */
16 | /* eslint-disable camelcase */
17 | import { OktaAuthOptions, OktaAuth } from '@okta/okta-auth-js';
18 |
19 | export function createConfig(config: Okta.ConfigParameters): Promise;
20 |
21 | export function getAuthClient(): OktaAuth;
22 |
23 | export function signIn(
24 | credentials?: Okta.Credentials
25 | ): Promise;
26 |
27 | export function signInWithBrowser(
28 | options?: Okta.BrowserOptions
29 | ): Promise;
30 |
31 | export function authenticate(
32 | { sessionToken }: { sessionToken: string }
33 | ): Promise;
34 |
35 | export function signOut(): Promise<{ resolve_type: string }>;
36 |
37 | export function getAccessToken(): Promise<{ access_token: string }>;
38 | export function getIdToken(): Promise<{ id_token: string }>;
39 | export function getUser(): Promise;
40 | export function getUserFromIdToken(): Promise;
41 | export function isAuthenticated(): Promise<{ authenticated: boolean }>;
42 |
43 | export function revokeAccessToken(): Promise;
44 | export function revokeIdToken(): Promise;
45 | export function revokeRefreshToken(): Promise;
46 |
47 | export function introspectAccessToken(): Promise;
48 | export function introspectIdToken(): Promise;
49 | export function introspectRefreshToken(): Promise;
50 |
51 | export function refreshTokens(): Promise;
52 | export function clearTokens(): Promise;
53 |
54 | import { NativeEventEmitter } from 'react-native';
55 |
56 | export const EventEmitter: NativeEventEmitter;
57 |
58 | export namespace Okta {
59 | interface ConfigParameters {
60 | issuer?: string;
61 | clientId: string;
62 | redirectUri: string;
63 | endSessionRedirectUri: string;
64 | discoveryUri: string;
65 | scopes: string[];
66 | requireHardwareBackedKeyStore: boolean;
67 | androidChromeTabColor?: string;
68 | httpConnectionTimeout?: number;
69 | httpReadTimeout?: number;
70 | browserMatchAll?: boolean;
71 | oktaAuthConfig?: OktaAuthOptions;
72 | }
73 |
74 | interface AuthenticationResponse {
75 | resolve_type: string;
76 | access_token: string;
77 | }
78 |
79 | interface RefreshResponse {
80 | access_token?: string;
81 | id_token?: string;
82 | refresh_token?: string;
83 | }
84 |
85 | interface Credentials {
86 | username: string;
87 | password: string;
88 | }
89 |
90 | interface BrowserOptions {
91 | idp?: string;
92 | noSSO?: boolean;
93 | login_hint?: string
94 | prompt?: string
95 | }
96 |
97 | interface StringAnyMap {
98 | [index: string]: string | number | boolean | StringAnyMap;
99 | }
100 | }
101 |
--------------------------------------------------------------------------------
/e2e/ios/E2EOktaReactNativeUITests/CustomLoginTests.swift:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2021-Present, Okta, Inc. and/or its affiliates. All rights reserved.
3 | * The Okta software accompanied by this notice is provided pursuant to the Apache License, Version 2.0 (the "License.")
4 | *
5 | * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0.
6 | * Unless required by applicable law or agreed to in writing, software
7 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
8 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
9 | *
10 | * See the License for the specific language governing permissions and limitations under the License.
11 | */
12 |
13 | import XCTest
14 |
15 | final class CustomLoginTests: LoginTests {
16 | private var signInButton: XCUIElement {
17 | app.buttons["sign_in_button"]
18 | }
19 |
20 | private var usernameTextField: XCUIElement {
21 | app.textFields["username_input"]
22 | }
23 |
24 | private var passwordTextField: XCUIElement {
25 | app.textFields["password_input"]
26 | }
27 |
28 | override func setUpWithError() throws {
29 | try super.setUpWithError()
30 | }
31 |
32 | func testLoginFlow() throws {
33 | // given
34 | XCTAssertTrue(customLoginButton.waitForExistence(timeout: .testing), app.debugDescription)
35 | // when
36 | customLoginButton.tap()
37 |
38 | // then
39 | XCTAssertTrue(usernameTextField.waitForExistence(timeout: .testing))
40 | XCTAssertTrue(passwordTextField.exists)
41 | XCTAssertTrue(signInButton.exists)
42 |
43 | usernameTextField.tap()
44 | usernameTextField.typeText(username)
45 |
46 | passwordTextField.tap()
47 | passwordTextField.typeText(password)
48 |
49 | signInButton.tap()
50 |
51 | XCTAssertTrue(welcomeLabel.waitForExistence(timeout: .testing))
52 | XCTAssertTrue(userNameLabel.waitForExistence(timeout: .testing))
53 | XCTAssertNotEqual(userNameLabel.label, "")
54 |
55 | app.terminate()
56 | app.launch()
57 |
58 | XCTAssertTrue(welcomeLabel.waitForExistence(timeout: .testing))
59 | XCTAssertTrue(userNameLabel.waitForExistence(timeout: .testing))
60 | XCTAssertNotEqual(userNameLabel.label, "")
61 |
62 | XCTAssertTrue(logoutButton.exists)
63 | logoutButton.tap()
64 |
65 | try testRootScreen()
66 | }
67 |
68 | func testIncorrectLoginFlow() throws {
69 | // given
70 | XCTAssertTrue(customLoginButton.waitForExistence(timeout: .testing), app.debugDescription)
71 | // when
72 | customLoginButton.tap()
73 | // then
74 | XCTAssertTrue(usernameTextField.waitForExistence(timeout: .testing))
75 | XCTAssertTrue(passwordTextField.exists)
76 |
77 | usernameTextField.tap()
78 | usernameTextField.typeText(username)
79 |
80 | passwordTextField.tap()
81 | passwordTextField.typeText("1123123")
82 |
83 | signInButton.tap()
84 |
85 | let alertOKButton = app.alerts.element.buttons["OK"]
86 |
87 | XCTAssert(alertOKButton.waitForExistence(timeout: .testing))
88 | alertOKButton.tap()
89 |
90 | XCTAssertTrue(usernameTextField.exists)
91 | XCTAssertTrue(passwordTextField.exists)
92 | XCTAssertTrue(signInButton.exists)
93 | }
94 |
95 | private func logoutIfPossible(throwError: Bool = false) {
96 | guard logoutButton.waitForExistence(timeout: 10) else {
97 | XCTAssertFalse(throwError)
98 | return
99 | }
100 |
101 | logoutButton.tap()
102 |
103 | XCTAssertTrue(browserLoginButton.waitForExistence(timeout: .testing))
104 | }
105 | }
106 |
--------------------------------------------------------------------------------
/ios/ReactNativeOktaSdkBridge.xcodeproj/xcshareddata/xcschemes/ReactNativeOktaSdkBridge.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
33 |
39 |
40 |
41 |
42 |
43 |
53 |
54 |
60 |
61 |
62 |
63 |
69 |
70 |
76 |
77 |
78 |
79 |
81 |
82 |
85 |
86 |
87 |
--------------------------------------------------------------------------------
/e2e/ios/E2EOktaReactNative/SplashScreen.storyboard:
--------------------------------------------------------------------------------
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 |
--------------------------------------------------------------------------------
/ios/Tests/Mocks/OktaOidcStateManager+Factory.swift:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2021-Present, Okta, Inc. and/or its affiliates. All rights reserved.
3 | * The Okta software accompanied by this notice is provided pursuant to the Apache License, Version 2.0 (the "License.")
4 | *
5 | * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0.
6 | * Unless required by applicable law or agreed to in writing, software
7 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
8 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
9 | *
10 | * See the License for the specific language governing permissions and limitations under the License.
11 | */
12 |
13 | import XCTest
14 | import OktaOidc
15 | @testable import ReactNativeOktaSdkBridge
16 |
17 | extension OktaOidcStateManager {
18 | // expires in 2037
19 | static let mockIdToken = """
20 | eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJ3d3cuZXhhbXBsZS5jb20iLCJpYXQiOjE2MTg0NzU1ODMsImV4cCI6MjEyMzM5NzE4MywiYXVkIjoid3d3LmV4YW1wbGUuY29tIiwic3ViIjoianJvY2tldEBleGFtcGxlLmNvbSIsIkdpdmVuTmFtZSI6IkpvaG5ueSIsIlN1cm5hbWUiOiJSb2NrZXQiLCJFbWFpbCI6Impyb2NrZXRAZXhhbXBsZS5jb20ifQ.WY2K4adyY9p--NN83REjZzZglUI7JjxPNvmI3VigGFo
21 | """
22 |
23 | static let mockAccessToken = mockIdToken
24 |
25 | static func makeOidcStateManager(with configuration: OktaOidcConfig) -> OktaOidcStateManager {
26 | let serviceConfig = OKTServiceConfiguration(authorizationEndpoint: URL(string: configuration.issuer)!,
27 | tokenEndpoint: URL(string: configuration.issuer)!,
28 | issuer: URL(string: configuration.issuer)!)
29 |
30 | let mockTokenRequest = OKTTokenRequest(configuration: serviceConfig,
31 | grantType: OKTGrantTypeRefreshToken,
32 | authorizationCode: nil,
33 | redirectURL: configuration.redirectUri,
34 | clientID: "nil",
35 | clientSecret: nil,
36 | scope: nil,
37 | refreshToken: nil,
38 | codeVerifier: nil,
39 | additionalParameters: nil)
40 |
41 | let mockTokenResponse = OKTTokenResponse(
42 | request: mockTokenRequest,
43 | parameters: [
44 | "access_token": "mockAccessToken" as NSCopying & NSObjectProtocol,
45 | "expires_in": Date().addingTimeInterval(3600).timeIntervalSince1970 as NSCopying & NSObjectProtocol,
46 | "token_type": "Bearer" as NSCopying & NSObjectProtocol,
47 | "id_token": mockIdToken as NSCopying & NSObjectProtocol,
48 | "refresh_token": "refreshToken" as NSCopying & NSObjectProtocol,
49 | "scope": "openid offline_access" as NSCopying & NSObjectProtocol
50 | ]
51 | )
52 |
53 | let mockAuthRequest = OKTAuthorizationRequest(
54 | configuration: serviceConfig,
55 | clientId: configuration.clientId,
56 | clientSecret: nil,
57 | scopes: ["openid", "email"],
58 | redirectURL: configuration.redirectUri,
59 | responseType: OKTResponseTypeCode,
60 | additionalParameters: nil
61 | )
62 |
63 | let mockAuthResponse = OKTAuthorizationResponse(
64 | request: mockAuthRequest,
65 | parameters: ["code": "mockAuthCode" as NSCopying & NSObjectProtocol]
66 | )
67 |
68 | let authState = OKTAuthState(authorizationResponse: mockAuthResponse, tokenResponse: mockTokenResponse)
69 | return OktaOidcStateManager(authState: authState)
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/e2e/pages/CustomLogin.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2021-Present, Okta, Inc. and/or its affiliates. All rights reserved.
3 | * The Okta software accompanied by this notice is provided pursuant to the Apache License, Version 2.0 (the "License.")
4 | *
5 | * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0.
6 | * Unless required by applicable law or agreed to in writing, software
7 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
8 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
9 | *
10 | * See the License for the specific language governing permissions and limitations under the License.
11 | */
12 |
13 | /* eslint-disable no-unused-vars */
14 | /* eslint-disable node/no-missing-import */
15 |
16 | import React from 'react';
17 | import {
18 | Alert,
19 | Button,
20 | StyleSheet,
21 | TextInput,
22 | View,
23 | ActivityIndicator
24 | } from 'react-native';
25 |
26 | import {
27 | signIn,
28 | introspectIdToken
29 | } from '@okta/okta-react-native';
30 |
31 | export default class CustomLogin extends React.Component {
32 |
33 | constructor(props) {
34 | super(props);
35 | this.state = {
36 | isLoading: false,
37 | username: '',
38 | password: '',
39 | };
40 | }
41 |
42 | async componentDidMount() {
43 |
44 | }
45 |
46 | signInCustom = () => {
47 | this.setState({ isLoading: true });
48 | signIn({ username: this.state.username, password: this.state.password })
49 | .then(() => {
50 | introspectIdToken()
51 | .then(idToken => {
52 | this.props.navigation.navigate('ProfilePage', { idToken: idToken, isBrowserScenario: false });
53 | }).finally(() => {
54 | this.setState({
55 | isLoading: false,
56 | username: '',
57 | password: '',
58 | });
59 | });
60 | })
61 | .catch(error => {
62 | // For some reason the app crashes when only one button exist (only with loaded bundle, debug is OK) 🤦♂️
63 | Alert.alert(
64 | "Error",
65 | error.message,
66 | [
67 | {
68 | text: "Cancel",
69 | onPress: () => console.log("Cancel Pressed"),
70 | style: "cancel"
71 | },
72 | { text: "OK", onPress: () => console.log("OK Pressed") }
73 | ]
74 | );
75 |
76 |
77 | this.setState({
78 | isLoading: false
79 | });
80 | });
81 | }
82 |
83 | render() {
84 | if (this.state.isLoading) {
85 | return (
86 |
87 |
88 |
89 | );
90 | }
91 |
92 | return (
93 |
94 | this.setState({ username: input })}
98 | testID="username_input"
99 | />
100 | this.setState({ password: input })}
104 | testID="password_input"
105 | />
106 |
111 |
112 |
113 | );
114 | }
115 | }
116 |
117 | const styles = StyleSheet.create({
118 | container: {
119 | flex: 1,
120 | backgroundColor: '#fff',
121 | alignItems: 'center',
122 | justifyContent: 'center',
123 | },
124 | input: {
125 | height: 40,
126 | width: '80%',
127 | margin: 12,
128 | borderWidth: 1,
129 | padding: 10,
130 | },
131 | flexible: {
132 | flex: 1,
133 | }
134 | });
135 |
--------------------------------------------------------------------------------
/android/build.gradle:
--------------------------------------------------------------------------------
1 | import groovy.json.JsonSlurper
2 |
3 | /*
4 | * Copyright (c) 2017, Okta, Inc. and/or its affiliates. All rights reserved.
5 | * The Okta software accompanied by this notice is provided pursuant to the Apache License, Version 2.0 (the "License.")
6 | *
7 | * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0.
8 | * Unless required by applicable law or agreed to in writing, software
9 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
10 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 | *
12 | * See the License for the specific language governing permissions and limitations under the License.
13 | */
14 |
15 | buildscript {
16 | apply from: 'forceVersions.gradle'
17 | forceVersions(configurations)
18 |
19 | repositories {
20 | google()
21 | mavenCentral()
22 | }
23 |
24 | dependencies {
25 | classpath('com.android.tools.build:gradle:8.4.1')
26 | }
27 | }
28 |
29 | plugins {
30 | id('maven-publish')
31 | }
32 |
33 | apply plugin: 'com.android.library'
34 |
35 | def safeExtGet(prop, fallback) {
36 | rootProject.ext.has(prop) ? rootProject.ext.get(prop) : fallback
37 | }
38 |
39 | def DEFAULT_COMPILE_SDK_VERSION = 34
40 | def DEFAULT_MIN_SDK_VERSION = 23
41 | def DEFAULT_TARGET_SDK_VERSION = 34
42 |
43 | android {
44 | namespace "com.oktareactnative"
45 | compileSdkVersion safeExtGet('compileSdkVersion', DEFAULT_COMPILE_SDK_VERSION)
46 |
47 | defaultConfig {
48 | minSdkVersion safeExtGet('minSdkVersion', DEFAULT_MIN_SDK_VERSION)
49 | targetSdkVersion safeExtGet('targetSdkVersion', DEFAULT_TARGET_SDK_VERSION)
50 | versionCode 1
51 | versionName "1.0"
52 | manifestPlaceholders = [
53 | "appAuthRedirectScheme": ""
54 | ]
55 | }
56 | lintOptions {
57 | abortOnError false
58 | }
59 | }
60 |
61 | allprojects {
62 | forceVersions(configurations)
63 |
64 | repositories {
65 | mavenCentral()
66 | google()
67 | maven { url 'https://www.jitpack.io' }
68 | }
69 | }
70 |
71 | dependencies {
72 | implementation "com.facebook.react:react-android:+"
73 | implementation 'com.okta.android:okta-oidc-android:1.3.4'
74 | implementation 'com.squareup.okhttp3:okhttp:4.12.0'
75 | implementation 'com.squareup.okio:okio:3.5.0'
76 | implementation 'com.squareup.okio:okio-jvm:3.5.0'
77 | }
78 |
79 | def configureReactNativePom(def pom) {
80 | def packageJson = new JsonSlurper().parseText(file('../package.json').text)
81 |
82 | pom.project {
83 | name packageJson.title
84 | artifactId packageJson.name
85 | version = packageJson.version
86 | group = "com.oktareactnative"
87 | description packageJson.description
88 | url packageJson.repository.baseUrl
89 |
90 | licenses {
91 | license {
92 | name packageJson.license
93 | url packageJson.repository.baseUrl + '/blob/master/' + packageJson.licenseFilename
94 | distribution 'repo'
95 | }
96 | }
97 | }
98 | }
99 |
100 | afterEvaluate { project ->
101 |
102 | task androidSourcesJar(type: Jar) {
103 | archiveClassifier = 'sources'
104 | from android.sourceSets.main.java.srcDirs
105 | include '**/*.java'
106 | }
107 |
108 | android.libraryVariants.all { variant ->
109 | def name = variant.name.capitalize()
110 | def javaCompileTask = variant.javaCompileProvider.get()
111 |
112 | task "jar${name}"(type: Jar, dependsOn: javaCompileTask) {
113 | from javaCompileTask.destinationDir
114 | }
115 | }
116 |
117 | artifacts {
118 | archives androidSourcesJar
119 | }
120 |
121 | publishing {
122 | publications {
123 | maven(MavenPublication) {
124 | artifact androidSourcesJar
125 | }
126 | }
127 | }
128 | }
129 |
--------------------------------------------------------------------------------
/e2e/ios/E2EOktaReactNative/Base.lproj/LaunchScreen.xib:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
22 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
--------------------------------------------------------------------------------
/e2e/pages/Home.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2021-Present, Okta, Inc. and/or its affiliates. All rights reserved.
3 | * The Okta software accompanied by this notice is provided pursuant to the Apache License, Version 2.0 (the "License.")
4 | *
5 | * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0.
6 | * Unless required by applicable law or agreed to in writing, software
7 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
8 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
9 | *
10 | * See the License for the specific language governing permissions and limitations under the License.
11 | */
12 |
13 | /* eslint-disable no-unused-vars */
14 | /* eslint-disable node/no-missing-import */
15 |
16 | import React from 'react';
17 | import {
18 | Button,
19 | StyleSheet,
20 | Text,
21 | View,
22 | Alert,
23 | ActivityIndicator
24 | } from 'react-native';
25 |
26 | import {
27 | createConfig,
28 | introspectAccessToken,
29 | introspectIdToken,
30 | signInWithBrowser,
31 | signOut,
32 | } from '@okta/okta-react-native';
33 |
34 | import configFile from './../config';
35 |
36 | export default class Home extends React.Component {
37 |
38 | constructor(props) {
39 | super(props);
40 | this.state = {
41 | authenticated: false,
42 | idToken: '',
43 | isLoading: false,
44 | };
45 | }
46 |
47 | async componentDidMount() {
48 | await createConfig({
49 | clientId: configFile.oidc.clientId,
50 | redirectUri: configFile.oidc.redirectUri,
51 | endSessionRedirectUri: configFile.oidc.endSessionRedirectUri,
52 | discoveryUri: configFile.oidc.discoveryUri,
53 | scopes: configFile.oidc.scopes,
54 | requireHardwareBackedKeyStore:
55 | configFile.oidc.requireHardwareBackedKeyStore
56 | });
57 |
58 | this.setInitialState();
59 | }
60 |
61 | setInitialState = () => {
62 | this.setState({ isLoading: true });
63 |
64 | introspectAccessToken()
65 | .then(() => {
66 | introspectIdToken()
67 | .then(idToken => {
68 | this.setState({ authenticated: true, idToken: idToken });
69 |
70 | this.props.navigation.navigate('ProfilePage', { idToken: idToken, isBrowserScenario: true });
71 | })
72 | .catch(error => {
73 | console.warn(error);
74 | this.setState({ authenticated: true, idToken: '' });
75 | })
76 | .finally(() => {
77 | this.setState({ isLoading: false });
78 | });
79 | })
80 | .catch(() => {
81 | this.setState({ authenticated: false, isLoading: false });
82 | });
83 | }
84 |
85 | signInBrowser = () => {
86 | signInWithBrowser()
87 | .then(() => {
88 | this.setInitialState();
89 | })
90 | .catch(error => {
91 | // Ignore cancellation error
92 | if (error.code == '-1200') {
93 | return;
94 | }
95 |
96 | console.warn(error);
97 |
98 | Alert.alert(
99 | error.message ?? 'Error occurred',
100 | [
101 | {
102 | text: 'OK',
103 | style: 'cancel'
104 | }
105 | ]
106 | );
107 | });
108 | }
109 |
110 | logout = () => {
111 | signOut().then(() => {
112 | this.setState({ authenticated: false });
113 | }).catch(error => {
114 | console.log(error);
115 | });
116 | }
117 |
118 | render() {
119 | if (this.state.isLoading) {
120 | return (
121 |
122 |
123 |
124 | );
125 | }
126 |
127 | return (
128 |
129 |
134 |
140 | );
141 | }
142 | }
143 |
144 | const styles = StyleSheet.create({
145 | container: {
146 | flex: 1,
147 | backgroundColor: '#fff',
148 | alignItems: 'center',
149 | justifyContent: 'center',
150 | },
151 | input: {
152 | height: 40,
153 | margin: 12,
154 | borderWidth: 1,
155 | padding: 10,
156 | },
157 |
158 | });
159 |
--------------------------------------------------------------------------------
/e2e/android/app/src/androidTest/java/com/e2eoktareactnative/web/WebPage.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023-Present Okta, Inc.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.e2eoktareactnative.web
17 |
18 | import android.app.Application
19 | import android.content.Intent
20 | import android.net.Uri
21 | import androidx.test.core.app.ApplicationProvider
22 | import androidx.test.platform.app.InstrumentationRegistry
23 | import androidx.test.uiautomator.By
24 | import androidx.test.uiautomator.UiDevice
25 | import androidx.test.uiautomator.UiSelector
26 | import androidx.test.uiautomator.Until
27 | import com.e2eoktareactnative.dashboard.DashboardPage
28 | import com.e2eoktareactnative.test.clickButtonWithSelector
29 | import com.e2eoktareactnative.test.clickButtonWithText
30 | import com.e2eoktareactnative.test.clickButtonWithTextMatching
31 | import com.e2eoktareactnative.test.execShellCommand
32 | import com.e2eoktareactnative.test.setTextForIndex
33 | import com.e2eoktareactnative.test.waitForText
34 | import timber.log.Timber
35 | import kotlin.time.Duration.Companion.seconds
36 |
37 | internal class WebPage(
38 | private val previousPage: PreviousPage,
39 | initialText: String = "Sign In"
40 | ) {
41 | companion object {
42 | // The login button text can also be "Sign in" with lower case 'i', depending on backend
43 | private val loginButtonSelector = UiSelector().text("Sign In").clickable(true)
44 |
45 | fun clearData() {
46 | execShellCommand("pm clear com.android.chrome")
47 | Thread.sleep(2.seconds.inWholeMilliseconds)
48 |
49 | val application = ApplicationProvider.getApplicationContext()
50 | val browserIntent = Intent(Intent.ACTION_VIEW, Uri.parse("https://okta.com"))
51 | val buttonTimeout = 1.seconds.inWholeMilliseconds
52 | browserIntent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
53 | application.startActivity(browserIntent)
54 |
55 | try {
56 | clickButtonWithText("Use without an account", buttonTimeout)
57 | } catch (e: Throwable) {
58 | Timber.e(e, "Error calling Use without an account")
59 | }
60 |
61 | try {
62 | clickButtonWithText("Accept & continue", buttonTimeout)
63 | } catch (e: Throwable) {
64 | Timber.e(e, "Error Calling accept and continue")
65 | }
66 |
67 | try {
68 | clickButtonWithTextMatching("No [t|T]hanks", buttonTimeout)
69 | } catch (e: Throwable) {
70 | Timber.e(e, "Error Calling No thanks")
71 | }
72 |
73 | Thread.sleep(1.seconds.inWholeMilliseconds)
74 | execShellCommand("am force-stop com.android.chrome")
75 | Thread.sleep(1.seconds.inWholeMilliseconds)
76 | }
77 | }
78 |
79 | init {
80 | waitForText(initialText)
81 | }
82 |
83 | fun username(username: String): WebPage {
84 | setTextForIndex(0, username)
85 | return this
86 | }
87 |
88 | fun password(password: String): WebPage {
89 | setTextForIndex(1, password)
90 | return this
91 | }
92 |
93 | fun login(): DashboardPage {
94 | clickButtonWithSelector(loginButtonSelector, timeout = 10.seconds.inWholeMilliseconds)
95 | return DashboardPage()
96 | }
97 |
98 | fun loginExpectingError(): WebPage {
99 | clickButtonWithSelector(loginButtonSelector, timeout = 10.seconds.inWholeMilliseconds)
100 | return this
101 | }
102 |
103 | fun cancel(): PreviousPage {
104 | val device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
105 | device.pressBack()
106 | device.wait(Until.findObject(By.pkg("com.e2eoktareactnative")), 2_000)
107 | return previousPage
108 | }
109 |
110 | fun assertHasError(error: String): WebPage {
111 | waitForText(error)
112 | return this
113 | }
114 | }
115 |
--------------------------------------------------------------------------------
/e2e/ios/E2EOktaReactNative.xcodeproj/xcshareddata/xcschemes/E2EOktaReactNative.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
33 |
36 |
37 |
38 |
39 |
40 |
42 |
48 |
49 |
50 |
51 |
52 |
62 |
64 |
70 |
71 |
72 |
73 |
77 |
78 |
82 |
83 |
84 |
85 |
91 |
93 |
99 |
100 |
101 |
102 |
104 |
105 |
108 |
109 |
110 |
--------------------------------------------------------------------------------
/e2e/ios/E2EOktaReactNativeUITests/BrowserLoginTests.swift:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2021-Present, Okta, Inc. and/or its affiliates. All rights reserved.
3 | * The Okta software accompanied by this notice is provided pursuant to the Apache License, Version 2.0 (the "License.")
4 | *
5 | * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0.
6 | * Unless required by applicable law or agreed to in writing, software
7 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
8 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
9 | *
10 | * See the License for the specific language governing permissions and limitations under the License.
11 | */
12 |
13 | import XCTest
14 |
15 | final class BrowserLoginTests: LoginTests {
16 | private let springboard = XCUIApplication(bundleIdentifier: "com.apple.springboard")
17 |
18 | private var springboardCancelButton: XCUIElement {
19 | springboard.buttons["Cancel"]
20 | }
21 |
22 | private var springboardContinueButton: XCUIElement {
23 | springboard.buttons["Continue"]
24 | }
25 |
26 | private var signInButton: XCUIElement {
27 | app.buttons["Sign In"]
28 | }
29 |
30 | func testLoginFlow() throws {
31 | // given
32 | XCTAssertTrue(browserLoginButton.waitForExistence(timeout: .testing))
33 | // when
34 | browserLoginButton.tap()
35 | // then
36 | XCTAssertTrue(springboardContinueButton.waitForExistence(timeout: .testing))
37 | springboardContinueButton.tap()
38 |
39 | let webView = app.webViews
40 |
41 | let usernameField = webView.textFields.element(boundBy: .zero)
42 | XCTAssertTrue(usernameField.waitForExistence(timeout: .testing))
43 | usernameField.tap()
44 | usernameField.typeText(username)
45 |
46 | let doneButton = app.toolbars.buttons["Done"]
47 | if doneButton.exists && doneButton.isHittable {
48 | doneButton.tap()
49 | }
50 |
51 | let passwordField = webView.secureTextFields.allElementsBoundByIndex.first(where: { $0.frame.width >= usernameField.frame.width })!
52 | passwordField.tap()
53 | passwordField.typeText(password)
54 |
55 | signInButton.tap()
56 |
57 | XCTAssertTrue(welcomeLabel.waitForExistence(timeout: .testing))
58 | XCTAssertTrue(userNameLabel.waitForExistence(timeout: .testing))
59 | XCTAssertNotEqual(userNameLabel.label, "")
60 |
61 | app.terminate()
62 | app.launch()
63 |
64 | XCTAssertTrue(welcomeLabel.waitForExistence(timeout: .testing))
65 | XCTAssertTrue(userNameLabel.waitForExistence(timeout: .testing))
66 | XCTAssertNotEqual(userNameLabel.label, "")
67 |
68 | logoutIfPossible(throwError: true)
69 | }
70 |
71 | func testCancelLoginFlow() throws {
72 | // given
73 | XCTAssertTrue(browserLoginButton.waitForExistence(timeout: .testing))
74 | // when
75 | browserLoginButton.tap()
76 | // then
77 | XCTAssertTrue(springboardCancelButton.waitForExistence(timeout: .testing))
78 | springboardCancelButton.tap()
79 |
80 | XCTAssertTrue(browserLoginButton.exists)
81 | XCTAssertTrue(customLoginButton.exists)
82 | }
83 |
84 | func testIncorrectLoginFlow() throws {
85 | // given
86 | XCTAssertTrue(browserLoginButton.waitForExistence(timeout: .testing))
87 | // when
88 | browserLoginButton.tap()
89 | // then
90 | XCTAssertTrue(springboardContinueButton.waitForExistence(timeout: .testing))
91 | springboardContinueButton.tap()
92 |
93 | let webView = app.webViews
94 |
95 | let usernameField = webView.textFields.element(boundBy: .zero)
96 | XCTAssertTrue(usernameField.waitForExistence(timeout: .testing))
97 | usernameField.tap()
98 | usernameField.typeText(username)
99 |
100 | let doneButton = app.toolbars.buttons["Done"]
101 | if doneButton.exists && doneButton.isHittable {
102 | doneButton.tap()
103 | }
104 |
105 | let passwordField = webView.secureTextFields.allElementsBoundByIndex.first { $0.frame.width >= usernameField.frame.width }!
106 | passwordField.tap()
107 | passwordField.typeText("1234567")
108 |
109 | signInButton.tap()
110 |
111 | app.buttons["Cancel"].tap()
112 |
113 | try testRootScreen()
114 | }
115 |
116 | private func logoutIfPossible(throwError: Bool = false) {
117 | guard logoutButton.waitForExistence(timeout: 10) else {
118 | XCTAssertFalse(throwError)
119 | return
120 | }
121 |
122 | logoutButton.tap()
123 |
124 | XCTAssertTrue(springboardContinueButton.waitForExistence(timeout: .testing))
125 | springboardContinueButton.tap()
126 |
127 | XCTAssertTrue(browserLoginButton.waitForExistence(timeout: .testing))
128 | }
129 | }
130 |
--------------------------------------------------------------------------------
/android/src/main/java/com/oktareactnative/HttpClientImpl.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2019, Okta, Inc. and/or its affiliates. All rights reserved.
3 | * The Okta software accompanied by this notice is provided pursuant to the Apache License, Version 2.0 (the "License.")
4 | *
5 | * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0.
6 | * Unless required by applicable law or agreed to in writing, software
7 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
8 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
9 | *
10 | * See the License for the specific language governing permissions and limitations under the License.
11 | */
12 |
13 | package com.oktareactnative;
14 |
15 | import static com.okta.oidc.net.ConnectionParameters.USER_AGENT;
16 |
17 | import android.net.Uri;
18 |
19 | import androidx.annotation.NonNull;
20 |
21 | import com.okta.oidc.BuildConfig;
22 | import com.okta.oidc.net.ConnectionParameters;
23 | import com.okta.oidc.net.OktaHttpClient;
24 |
25 | import java.io.IOException;
26 | import java.io.InputStream;
27 | import java.util.List;
28 | import java.util.Map;
29 | import java.util.concurrent.CountDownLatch;
30 | import java.util.concurrent.TimeUnit;
31 |
32 | import okhttp3.Call;
33 | import okhttp3.Callback;
34 | import okhttp3.FormBody;
35 | import okhttp3.OkHttpClient;
36 | import okhttp3.Request;
37 | import okhttp3.RequestBody;
38 | import okhttp3.Response;
39 |
40 | public class HttpClientImpl implements OktaHttpClient {
41 | private final String userAgentTemplate;
42 | private final int connectTimeoutMs;
43 | private final int readTimeoutMs;
44 | protected static OkHttpClient sOkHttpClient;
45 | protected volatile Call mCall;
46 | protected Response mResponse;
47 | protected Exception mException;
48 |
49 | HttpClientImpl(String userAgentTemplate, int connectTimeoutMs, int readTimeoutMs) {
50 | this.userAgentTemplate = userAgentTemplate;
51 | this.connectTimeoutMs = connectTimeoutMs;
52 | this.readTimeoutMs = readTimeoutMs;
53 | }
54 |
55 | private String getUserAgent() {
56 | String sdkVersion = "okta-oidc-android/" + BuildConfig.VERSION_NAME;
57 | return userAgentTemplate.replace("$UPSTREAM_SDK", sdkVersion);
58 | }
59 |
60 | protected Request buildRequest(Uri uri, ConnectionParameters param) {
61 | if (sOkHttpClient == null) {
62 | sOkHttpClient = new OkHttpClient.Builder()
63 | .connectTimeout(connectTimeoutMs, TimeUnit.MILLISECONDS)
64 | .readTimeout(readTimeoutMs, TimeUnit.MILLISECONDS)
65 | .followRedirects(false)
66 | .build();
67 | }
68 | Request.Builder requestBuilder = new Request.Builder().url(uri.toString());
69 | requestBuilder.addHeader(USER_AGENT, getUserAgent());
70 | for (Map.Entry headerEntry : param.requestProperties().entrySet()) {
71 | String key = headerEntry.getKey();
72 | requestBuilder.addHeader(key, headerEntry.getValue());
73 | }
74 | if (param.requestMethod() == ConnectionParameters.RequestMethod.GET) {
75 | requestBuilder = requestBuilder.get();
76 | } else {
77 | Map postParameters = param.postParameters();
78 | if (postParameters != null) {
79 | FormBody.Builder formBuilder = new FormBody.Builder();
80 | for (Map.Entry postEntry : postParameters.entrySet()) {
81 | String key = postEntry.getKey();
82 | formBuilder.add(key, postEntry.getValue());
83 | }
84 | RequestBody formBody = formBuilder.build();
85 | requestBuilder.post(formBody);
86 | } else {
87 | requestBuilder.post(RequestBody.create(null, ""));
88 | }
89 | }
90 | return requestBuilder.build();
91 | }
92 |
93 | @Override
94 | public InputStream connect(@NonNull Uri uri, @NonNull ConnectionParameters params)
95 | throws Exception {
96 | Request request = buildRequest(uri, params);
97 | mCall = sOkHttpClient.newCall(request);
98 | final CountDownLatch latch = new CountDownLatch(1);
99 | mCall.enqueue(new Callback() {
100 | @Override
101 | public void onFailure(Call call, IOException e) {
102 | mException = e;
103 | latch.countDown();
104 | }
105 |
106 | @Override
107 | public void onResponse(Call call, Response response) {
108 | mResponse = response;
109 | latch.countDown();
110 | }
111 | });
112 | latch.await();
113 | if (mException != null) {
114 | throw mException;
115 | }
116 | if (mResponse != null && mResponse.body() != null) {
117 | return mResponse.body().byteStream();
118 | }
119 | return null;
120 | }
121 |
122 | @Override
123 | public void cleanUp() {
124 | //NO-OP
125 | }
126 |
127 | @Override
128 | public void cancel() {
129 | if (mCall != null) {
130 | mCall.cancel();
131 | }
132 | }
133 |
134 | @Override
135 | public Map> getHeaderFields() {
136 | if (mResponse != null) {
137 | return mResponse.headers().toMultimap();
138 | }
139 | return null;
140 | }
141 |
142 | @Override
143 | public String getHeader(String header) {
144 | if (mResponse != null) {
145 | return mResponse.header(header);
146 | }
147 | return null;
148 | }
149 |
150 | @Override
151 | public int getResponseCode() throws IOException {
152 | if (mResponse != null) {
153 | return mResponse.code();
154 | }
155 | return -1;
156 | }
157 |
158 | @Override
159 | public int getContentLength() {
160 | if (mResponse != null && mResponse.body() != null) {
161 | return (int) mResponse.body().contentLength();
162 | }
163 | return -1;
164 | }
165 |
166 | @Override
167 | public String getResponseMessage() throws IOException {
168 | if (mResponse != null) {
169 | return mResponse.message();
170 | }
171 | return null;
172 | }
173 | }
174 |
--------------------------------------------------------------------------------