Giter Club home page Giter Club logo

okta-oidc-ios's Introduction

CI Status Carthage compatible Version License Platforms Swift

Okta Open ID Connect Library

This is a new version of this SDK, the new pod name is OktaOidc. The old OktaAuth pod is now deprecated.

This library is a Swift wrapper around the AppAuth-iOS Objective-C code for communicating with Okta as an OAuth 2.0 + OpenID Connect provider, and follows current best practice for native apps using Authorization Code Flow + PKCE.

You can learn more on the Okta + iOS page in our documentation. You can also download our sample application.

Table of Contents

Getting Started

Installing the OktaOidc SDK into your project is simple. The easiest way to include this library into your project is through CocoaPods.

You'll also need:

  • An Okta account, called an organization (sign up for a free developer organization if you need one).
  • An Okta Application, configured as a Native App. This is done from the Okta Developer Console and you can find instructions here. When following the wizard, use the default properties. They are designed to work with our sample applications.

Note: If you would like to use your own in-app user interface instead of the web browser, you can do so by using our Swift Authentication SDK.

Supported Platforms

iOS

Okta OIDC supports iOS 11 and above.

macOS

Okta OIDC supports macOS (OS X) 10.14 and above. Library supports both custom schemes; a loopback HTTP redirects via a small embedded server.

Install

Swift Package Manager

Add the following to the dependencies attribute defined in your Package.swift file. You can select the version using the majorVersion and minor parameters. For example:

    dependencies: [
        .Package(url: "https://github.com/okta/okta-oidc-ios.git", majorVersion: <majorVersion>, minor: <minor>)
    ]

Cocoapods

Simply add the following line to your Podfile:

pod 'OktaOidc'

Then install it into your project:

pod install --repo-update

Carthage

To integrate this SDK into your Xcode project using Carthage, specify it in your Cartfile:

github "okta/okta-oidc-ios"

Then install it into your project:

carthage update --use-xcframeworks

Note: Make sure Carthage version is 0.37.0 or higher. Otherwise, Carthage can fail.

Usage Guide

For an overview of this library's features and authentication flows, check out our developer docs.

You can also browse the full API reference documentation.

Configuration Reference

Create OIDC object

Before using this SDK you have to create a new object of OktaOidc. You can instantiate OktaOidc w/o parameters that means that SDK will use Okta.plist for configuration values. Alternatively you can create OktaOidc with custom configuration.

import OktaOidc

// Use the default Okta.plist configuration
let oktaOidc = OktaOidc()

// Use configuration from another resource
let config = OktaOidcConfig(/* plist */)
let config = OktaOidcConfig(/* dictionary */)

// Instantiate OktaOidc with custom configuration object
let oktaOidc = OktaOidc(configuration: config)

Need a refresh token? A refresh token is a special token that is used to generate additional access and ID tokens. Make sure to include the offline_access scope in your configuration to silently renew the user's session in your application!

Property list

The easiest way is to create a property list in your application's bundle. By default, this library checks for the existence of the file Okta.plist. However any property list file can be used to create configuration object. Ensure one is created with the following fields:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
  <dict>
    <key>issuer</key>
    <string>https://{yourOktaDomain}.com/oauth2/default</string>
    <key>clientId</key>
    <string>{clientId}</string>
    <key>redirectUri</key>
    <string>{redirectUri}</string>
    <key>logoutRedirectUri</key>
    <string>{logoutRedirectUri}</string>
    <key>scopes</key>
    <string>openid profile offline_access</string>
  </dict>
</plist>

Configuration object

Alternatively, you can create a configuration object (OktaOidcConfig) from dictionary with the required values:

let configuration = OktaOidcConfig(with: [
  "issuer": "https://{yourOktaDomain}/oauth2/default",
  "clientId": "{clientID}",
  "redirectUri": "{redirectUri}",
  "logoutRedirectUri": "{logoutRedirectUri}",
  "scopes": "openid profile offline_access",
  // Custom parameters
  "login_hint": "[email protected]"
])

Disable Single Sign-On for the authentication session

You can disable SSO capabilities by setting noSSO flag to true for OktaOidcConfig instance.

let configuration = OktaOidcConfig(with: {YourOidcConfiguration})
if #available(iOS 13.0, *) {
    configuration?.noSSO = true
}

Note Flag is available on iOS 13 and above versions

Token Time Validation

Custom token time validation is possible by adopting to OKTTokenValidator protocol and then setting tokenValidator variable:

configuration?.tokenValidator = self

By default OKTDefaultTokenValidator object is set.

How to use in Objective-C project

To use this SDK in Objective-C project, you should do the following:

  • Add use_frameworks! in your Pod file.
  • Add project setting SWIFT_VERSION = 5.0. To do this open Build Settings in Xcode, select Edit -> Add Build setting -> Add User-Defined Setting. Specify SWIFT_VERSION and 5.0 as setting name and value correspondently.
  • Include autogenerated header OktaOidc/OktaOidc-Swift.h into your source code.

API Reference

signInWithBrowser

Start the authorization flow by simply calling signInWithBrowser. In case of successful authorization, this operation will return valid OktaOidcStateManager in its callback. Clients are responsible for further storage and maintenance of the manager.

Note: IDP can be passed by specifying an argument with the idp parameter.

iOS

oktaOidc.signInWithBrowser(from: viewController, additionalParameters: ["idp": "your_idp_here"]) { stateManager, error in
  if let error = error {
    // Error
    return
  }

  // stateManager.accessToken
  // stateManager.idToken
  // stateManager.refreshToken
}

Sample app example.

macOS

// Create redirect server configuration and start local HTTP server if you don't want to use custom schemes
let serverConfig = OktaRedirectServerConfiguration.default
serverConfig.port = 63875
oktaOidc.signInWithBrowser(redirectServerConfiguration: serverConfig, additionalParameters: ["idp": "your_idp_here"]) { stateManager, error in
  if let error = error {
    // Error
    return
  }

  // stateManager.accessToken
  // stateManager.idToken
  // stateManager.refreshToken
}

signOutOfOkta

This method ends the user's Okta session in the browser. The method deletes Okta's persistent cookie and disables SSO capabilities.

Important: This method does not clear or revoke tokens minted by Okta. Use the revoke and clear methods of OktaOidcStateManager to terminate the user's local session in your application.

iOS

// Redirects to the configured 'logoutRedirectUri' specified in Okta.plist.
oktaOidc.signOutOfOkta(authStateManager, from: viewController) { error in
  if let error = error {
    // Error
    return
  }
}

Sample app example.

macOS

// Create redirect server configuration and start local HTTP server if you don't want to use custom schemes
let serverConfig = OktaRedirectServerConfiguration.default
serverConfig.port = 63875
// Redirects to the configured 'logoutRedirectUri' specified in Okta.plist.
oktaOidc.signOutOfOkta(authStateManager: authStateManager, redirectServerConfiguration: serverConfig) { error in
  if let error = error {
    // Error
    return
  }
}

signOut

This method helps to perform a multi-step sign-out flow. The method provides options that you want to perform and the SDK runs the options as a batch. The available options are:

  • revokeAccessToken - SDK revokes access token
  • revokeRefreshToken - SDK revokes refresh token
  • removeTokensFromStorage - SDK removes tokens from the secure storage
  • signOutFromOkta - SDK calls signOutOfOkta
  • revokeTokensOptions - revokes access and refresh tokens
  • allOptions - revokes tokens, signs out from Okta, and removes tokens from the secure storage

The order of operations performed by the SDK:

  1. Revoke the access token, if the option is set. If this step fails step 3 will be omitted.
  2. Revoke the refresh token, if the option is set. If this step fails step 3 will be omitted.
  3. Remove tokens from the secure storage, if the option is set.
  4. Browser sign out, if the option is set.

iOS

let options: OktaSignOutOptions = .revokeTokensOptions
options.insert(.signOutFromOkta)
oktaOidc?.signOut(authStateManager: authStateManager, from: viewController, progressHandler: { currentOption in
    if currentOption.contains(.revokeAccessToken) {
        // update progress
    } else if currentOption.contains(.revokeRefreshToken) {
        // update progress
    } else if currentOption.contains(.signOutFromOkta) {
        // update progress
    }
}, completionHandler: { success, failedOptions in
    if !success {
        // handle error
    }
})

macOS

// Create redirect server configuration and start local HTTP server if you don't want to use custom schemes
let serverConfig = OktaRedirectServerConfiguration.default
serverConfig.port = 63875
let options: OktaSignOutOptions = .revokeTokensOptions
options.insert(.signOutFromOkta)
oktaOidc?.signOut(authStateManager: authStateManager,
                  redirectServerConfiguration: serverConfig,
                  progressHandler: { currentOption in
    if currentOption.contains(.revokeAccessToken) {
        // update progress
    } else if currentOption.contains(.revokeRefreshToken) {
        // update progress
    } else if currentOption.contains(.signOutFromOkta) {
        // update progress
    }
}, completionHandler: { success, failedOptions in
    if !success {
        // handle error
    }
})

authenticate

If you already signed in to Okta and have a valid session token, you can complete authorization by calling authenticate(withSessionToken:). Upon successful authorization, this operation returns a valid OktaOidcStateManager in the callback. Clients are responsible for further storage and maintenance of the manager.

oktaOidc.authenticate(withSessionToken: token) { stateManager, error in
  self.hideProgress()
  if let error = error {
    // Error
    return
  }

  // stateManager.accessToken
  // stateManager.idToken
  // stateManager.refreshToken
}

Sample app example.

stateManager

Tokens are securely stored in the Keychain and can be retrieved by accessing the OktaOidcStateManager.

stateManager?.accessToken
stateManager?.idToken
stateManager?.refreshToken

User is responsible for storing OktaAuthStateManager returned by signInWithBrowser or authenticate operation. To store manager call the writeToSecureStorage method:

oktaOidc.signInWithBrowser(from: self) { stateManager, error in
  stateManager.writeToSecureStorage()
}

Sample app example.

To retrieve stored manager call readFromSecureStorage(for:) and pass here Okta configuration that corresponds to a manager you are interested in.

guard let stateManager = OktaOidcStateManager.readFromSecureStorage(for: oktaConfig) else {
    // unauthenticated
}

//authenticated 
// stateManager.accessToken
// stateManager.idToken
// stateManager.refreshToken

Sample app example.

Note: In OktaOidc SDK 3.0 we added support for multiple Oauth 2.0 accounts. So developer can use Okta endpoint, social endpoint and others in one application. Therefore OktaOidcStateManager is stored in keychain using composite key constructed based on configuration. For backward compatibility there is a method readFromSecureStorage() that tries to read OktaOidcStateManager stored on a legacy way, so user could retrieve previously stored OktaOidcStateManager after switching to a newer version of SDK.

introspect

Calls the introspection endpoint to inspect the validity of the specified token.

stateManager?.introspect(token: accessToken, callback: { payload, error in
  guard let isValid = payload["active"] as? Bool else {
    // Error
    return
  }

  print("Is token valid? \(isValid)")
})

Sample app example.

renew

Since access tokens are traditionally short-lived, you can renew expired tokens by exchanging a refresh token for new ones. See the configuration reference to ensure your app is configured properly for this flow.

stateManager?.renew { newAccessToken, error in
  if let error = error else {
    // Error
    return
  }

  // renewed TokenManager
}

Sample app example.

revoke

Calls the revocation endpoint to revoke the specified token.

stateManager?.revoke(accessToken) { response, error in
  if let error = error else {
    // Error
    return
  }

  // Token was revoked
}

Sample app example.

getUser

Calls the OpenID Connect UserInfo endpoint with the stored access token to return user claim information.

stateManager?.getUser { response, error in
  if let error = error {
    // Error
    return
  }

  // JSON response
}

Sample app example.

clear

Removes the local authentication state by removing cached tokens in the keychain.

Warning: SDK deletes all keychain items accessible to an application.

stateManager.clear()

Sample app example.

Development

Running Tests

To perform an end-to-end test, update the Okta.plist file to match your configuration as specified in the prerequisites. Next, export the following environment variables:

export USERNAME={username}
export PASSWORD={password}
export CLIENT_ID={clientId}
export ISSUER=https://{yourOktaDomain}/oauth2/default
export REDIRECT_URI={redirectUri}
export LOGOUT_REDIRECT_URI={logoutRedirectUri}

# Run E2E end Unit tests
bash ./scripts/build-and-test.sh

Note: You may need to update the emulator device to match your Xcode version.

Modify network requests

You can track and modify network requests made by OktaOidc. In order to do this, create an object conforming to the OktaNetworkRequestCustomizationDelegate protocol and set it to the requestCustomizationDelegate property on an OktaOidcConfig instance.

let configuration = OktaOidcConfig(with: {YourOidcConfiguration})
configuration.requestCustomizationDelegate = {YourDelegateInstance}

For example, delegate could be implemented as follows:

extension SomeNSObject: OktaNetworkRequestCustomizationDelegate {

    func customizableURLRequest(_ request: URLRequest?) -> URLRequest? {
        guard var modifiedRequest = request else {
            return nil
        }
        modifiedRequest.setValue("Some value", forHTTPHeaderField: "custom-header-field")
        print("Okta OIDC network request: \(modifiedRequest)")
        return modifiedRequest
    }

    func didReceive(_ response: URLResponse?) {
        guard let response = response else {
            return
        }
        print("Okta OIDC network response: \(response)")
    }
}

Note: It is highly recommended to copy all of the existing parameters from the original URLRequest object to modified request without any changes. Altering of this data could lead network request to fail. If customizableURLRequest(_:) method returns nil default request will be used.

Migration

Migrating from 3.10.x to 3.11.x

The SDK okta-oidc-ios has a major changes in error handling. Consider these guidelines to update your code.

  • APIError is renamed as api.
  • api error has the additional parameter underlyingError, it's an optional and indicates the origin of the error.
  • Introduced a new error authorization(error:description:).
  • authorization error appears when authorization server fails due to errors during authorization.
  • unexpectedAuthCodeResponse(statusCode:) has an error code parameter.
  • OktaOidcError conforms to CustomNSError protocol. It means you can convert the error to NSError and get code, userInfo, domain, underlyingErrors.
  • OktaOidcError conforms to Equatable protocol. The errors can be compared for equality using the operator == or inequality using the operator !=.

Known issues

iOS shows permission dialog({App} Wants to Use {Auth Domain} to Sign In) for Okta Sign Out flows

Known iOS issue where iOS doesn't provide any good ways to terminate active authentication session and delete SSO cookies. The only proper way for now is to use ASWebAuthenticationSession class to terminate the session. ASWebAuthenticationSession deletes all SSO cookies however shows Sign In persmissions dialog 🤯

You can also consider the following workarounds:

  • Use noSSO option in OIDC configuration object if you don't need SSO capabilites. Also note that this option works only on iOS 13+ versions
  • Fork repository and change user-agent implementation(OIDExternalUserAgentIOS.m) to use SFSafariViewController only. Some pitfalls of this approach described here.

Contributing

We welcome contributions to all of our open-source packages. Please, see the contribution guide to understand how to structure a contribution.

okta-oidc-ios's People

Contributors

allebedew avatar anastasiiaiurok-okta avatar arunthotta-okta avatar blairmitchelmore-okta avatar boryskasianenko-okta avatar brennerryan-okta avatar ildarabdullin-okta avatar jmaldonado-okta avatar jmelberg-okta avatar lihaoli-okta avatar mikenachbaur-okta avatar oleggnidets-okta avatar rajdeepnanua-okta avatar robertjd avatar tbelote-okta avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

okta-oidc-ios's Issues

Cocoapod version not the current master version

I'm not sure what's happening with signOutFromOkta, but it's clear there there are some versioning issues. When I updated to the latest pod and try to use the method signOutFromOktaas documented in the Readme file, it's not found. Then I looked at the example project and it uses a method namedsignOutOfOkta`. When I look at it's pod files, while supposedly being the same version they quite different. For example:

My Pods -

Using AppAuth (0.91.0)
Installing HydraAsync (1.0.2)
Installing OktaAuth 1.0.1 (was 0.3.0 and source changed to `https://github.com/CocoaPods/Specs.git` from `https://github.com/cocoapods/specs.git`)
Installing OktaJWT (1.0.0)
Installing Vinculum (0.2.0)

OktaAppAuth.swift lines 29-42

// Token manager
public var tokens: OktaTokenManager?

public func login(_ username: String, password: String) -> Login {
    // Authenticate via Resource Owner Password Grant
    return Login(forUsername: username, forPassword: password)
}

public func login() -> Login {
    // Authenticate via authorization code flow
    return Login()
}

public func isAuthenticated() -> Bool {

Example Project Pods -

Installing HydraAsync (1.2.1)
Installing OktaAppAuth (1.0.0.beta-okta)
Installing OktaAuth (1.0.1)

OktaAppAuth.swift lines 29-42

public var tokens: OktaTokenManager?

public func login() -> Login {
    // Authenticate via authorization code flow
    return Login()
}

public func signOutOfOkta() -> Logout {
    // End the Okta session
    return Logout()
}

public func isAuthenticated() -> Bool {

So, it looks like there is signOut in the example, and looking through the source in the master repo it's there as well, but it's not the same code as the Readme, or the publicly available pod. And the example has obviously different dependencies. (Updated HydraAsync, OktaAppAuth, no Vinculum). Maybe the cocoapod isn't pointing to the latest code, I'm not sure.

SFAuthenticationSession popup

Hello,

On iOS 11+ There is a popup that says " Wants to Use '' to Sign in".

This is in relation to SFAuthenticationSession which has the following footnote at https://developer.apple.com/documentation/safariservices/sfauthenticationsession

If an application uses SFAuthenticationSession, users are prompted by a dialog to give explicit consent, allowing the application to access the website's data in Safari. When the webpage is presented, it runs in a separate process, so the user and web service are guaranteed that the app has no way to gain access to the user’s credentials. Instead, the app gets a unique authentication token.

Is there any workaround we could have to get around having this UIAlertView pop up that is very breaking in user experience with logging in?

Thanks

Use User-Agent header

Right now we send "X-Okta-User-Agent-Extended", but we should use "User-Agent" to be consistent with other libraries have have the ability to use this header.

How to set authorization server

I get errors validating tokens due to authentication does not happen against the authorization server for my app.
How can I set authorization server?
Any chance this is fixed in pull request #12 ?

Easier management of authentication state

Currently the OktaKeychain methods are not available due to being internal functions. At the very least, the get method should be public.

This creates the ability to:

  1. Check for accessToken, idToken, or authState on app boot
  2. Create a new OktaTokenManager object based on the stored authState (since it is currently only created on successful authorization)

In short, you should be able to show/hide the login via:

if let authState = OktaKeychain.get("oktaAuthContext") {
  // Set the current session based on previous auth context
  OktaAuth.tokens = OktaTokenManager(authState)
} else {
  // User is not logged in. Perform the login flow
}

PKCE not implemented?

Trying to login using code-supplied username + password, but it only works if I add the client_id and client_secret. Is PKCE implemented at all?

Login Does Nothing

UPDATED I was going upgrade to the the 1.0.1 pod for our app, and when I installed the updated pod and made the required code changes, login no longer functions. Nothing happens. Even when using the given code sample. Neither print statement ever fires.

OktaAuth
 .login()
 .start(self)
 .then { tokens in
   print(tokens)
  }
 .catch { error in
   print(error)
  }

Here's my other pods and versions:

Using AppAuth (0.91.0)
Using BNRDeferred (4.0.0-beta.3)
Using CFAServices (0.2.0)
Using GoogleAnalytics (3.17.0)
Using HockeySDK (5.1.4)
Using HydraAsync (1.0.2)
Using KeychainAccess (3.1.2)
Using OktaAuth (1.0.1)
Using OktaJWT (1.0.0)
Using SwiftLint (0.29.3)
Using UrbanAirship-iOS-SDK (10.0.3)
Using Vinculum (0.2.0)

Invalid_client even right credential & client id?

OktaAuth .login()

UserInfo={NSLocalizedDescription={"error":"invalid_client","error_description":"Client authentication failed. Either the client or the client credentials are invalid."}}}}

I'm really confuse. I'm sure what I input is right and client id is valid
Later, I tried by harding the email and password phrases, I can login successfully.
OktaAuth.login(m_email, password: mPassword)

I dont know why I cannot login by webview.
Anyone can help me?

Rename login method

We are moving our documentation towards "sign in" instead of "login". We should rename the .login() method in this library to match.

Additionally, since we are adding a non-browser way to sign in (in #82), we should differentiate these methods.

I think the login() method should be renamed to signInWithBrowser(). What do you think @jmelberg-okta @ayurok?

Sign out method

With #87, we are adding the ability to sign out of Okta (end the Okta session). We also need to add and document a method for signing out of the app (destroying the user's tokens). This method should:

  1. Throw away tokens stored in the Keychain (i.e. clearAuthState())
  2. Revoke access and refresh tokens

We should give developers the ability to skip (2) if they do not want to incur a network request. However, the default should be true (revoke).

Note that the user may have an access token and may have a refresh token, but they will not always have one or both. This method must check to see whether either of those token types are stored, and revoke them if they exist and if the developer did not pass a parameter to disable revocation.

In Swift 3, unwrapping redirectUri causes crash

                // Build the Authentication request
                let request = OIDTokenRequest(
                           configuration: oidConfig,
                               grantType: grantType,
                       authorizationCode: authCode,
                             redirectURL: URL(string: redirectUri)!,
                                clientID: clientId,
                            clientSecret: clientSecret,
                                  scopes: Utils.scrubScopes(config["scopes"]),
                            refreshToken: refreshToken,
                            codeVerifier: nil,
                    additionalParameters: additionalParams
                )
                // Build the Authentication request
                let request = OIDAuthorizationRequest(
                           configuration: oidConfig,
                                clientId: clientId,
                                  scopes: Utils.scrubScopes(config["scopes"]),
                             redirectURL: URL(string: redirectUri)!,
                            responseType: OIDResponseTypeCode,
                    additionalParameters: Utils.parseAdditionalParams(config)
                )

Change to:
redirectURL: URL(string: redirectUri.addingPercentEncoding(withAllowedCharacters: NSCharacterSet.urlQueryAllowed)!)!,

Set clientSecret for okta-sdk programatically

We are integrating Okta into our mobile applications. We are following resource owner password flow and okta sdk (https://github.com/okta/okta-sdk-appauth-ios).

In the documentation (readme) it says that If using the Resource Owner Password Grant, you must specify the clientSecret in Okta.plist. But it also mention that IMPORTANT: It is strongly discouraged to store a clientSecret on a distributed app. Please refer to OAuth 2.0 for Native Apps for more information.

So how can we set/update the clientSecret from the code (programmatically)? I could not find any method to set clientSecret in the SDK.

If we are using okta.plist, the how to changed the endpoints, clientSecret etc for different environments?

Build demo of native login

Some customers can't use the AppAuth pattern (opening a browser and handling a callback to the app) because they want to have complete control over the UI/UX of the login experience. In other words, they want to have a totally native, in-app UI for login. The SDK will need a number of improvements to support this.

Before building the full solution, we should build a demo to validate that the proposed flow against Okta makes sense. This demo does not need to use the existing SDK.

Here is the login flow:

  1. Use an HTTP client to POST to the Authentication API. Send a username and password to perform primary authentication. The Authentication API will return a sessionToken.
  2. Construct a request for the Authorization Code + PKCE flow. Include an optional parameter: &sessionToken= with the value of the sessionToken from the Authentication API response. Include scope offline_access to request a refresh token.
  3. If the response has HTTP status code 302, parse the response headers to get the code from the Location header: {redirectUri}?code=foobar
  4. Construct the code exchange request to get access, ID, and refresh tokens in the app.

Crashes UI tests

I set everything up as per the readme file and it works as expected. However, when trying to run SWIFT UI tests, as soon as you click on the login or password field, XCODE crashes

Update documentation

These things are not currently documented:

  • How to sign the user out of the app
  • How to end the Okta session (after #87) is merged
  • An example of how to get the access token from the tokenManager and use it when making an HTTP call
  • How to pass additional parameters to the /authorize endpoint
    And we need to confirm that these things are removed from documentation
  • Anything relating to resource owner password flow/client secret

Cannot stay logged in after token expires

Hello,

I'm finding problems related to expired tokens.

Let's say I grab a token at 10am. That token expires at 11am (1 hour later) but I can use the refresh token to grab a new access token.

Example situations I've run into:

  1. I kill my app at 10:15am and launch it again at 10:30am. In the OktaAuth.isAuthenticated() it properly loads the previously created access token as expected and the app works as normal.

  2. I leave my app open until 11am, when I check the validity of my token. I see it has expired. I then call OktaAuth.refresh().then etc. etc. and as expected I successfully get an access token. Everything works great for my app until I kill it and launch it again. OktaAuth now has a problem retrieving tokens in the OktaAuth isAuthenticated() function even though I was able to successfully refresh the access token. It fails at unarchiving the Token Manager and thus I cannot refresh the auth token

  3. After authenticating at 10am I close my app at 10:15am, with still an access token expiration date of 11am . I launch it at 11:15am, which would mean that my access token expired 15 minutes earlier, so I would expect to be able to use the refresh token to get a fresh access token, but as I found in the previous situation, upon trying unarchive the token manager it fails to set the tokens and thus there is no refresh token to use.

This has basically made our app very hard to use as the okta-sdk-appauth-ios has a hard time reloading it's tokens once they have expired on a fresh launch, thus causing each of our users having to log in nearly every time they use the app.

Have the Okta engineers validated that they are able to successfully refresh the app from a cold start with an access token expired?

Thanks

Login is hanging

I just updated to 1.0.1 from 0.3.0, made the very minor code changes to accommodate the Hydra promise flow. Made the changes needed to the Okta.plist. Made the switch to point my pods to this repo, instead of the out of date Cocoapods version. And now "Sign In" is just hanging. I can put in the user name and password and then I get a permanent hang on this screen. At this point in the code, I don't have control of the screen, so I don't think the error is in my code. And I've confirmed everything is working as expected when I roll back the code, so I don't think there is something wrong with the service.

My only hunch is that it's something wrong with the callback into the app.

I'll keep digging.

Screen Shot

simulator screen shot - iphone xs max - 2019-01-09 at 15 37 21

Swift client for Authentication API

We need to build an SDK for Swift that communicates with our Authentication API (https://developer.okta.com/docs/api/resources/authn). This will be in a new repo (https://github.com/okta/okta-auth-swift).

Here is an example of an existing authentication SDK: https://github.com/okta/okta-auth-java

The product and technical requirements for these SDKs is here:
https://oktawiki.atlassian.net/wiki/spaces/PM/pages/584942575/Authentication+SDK+product+spec
https://oktawiki.atlassian.net/wiki/spaces/eng/pages/463831327/Technical+Design+for+AuthN+SDKs

The requirements for the MVP are in https://github.com/okta/okta-auth-swift/issues

iat validation without leeway is wrong

The OktaJWTVerifier.isIssuedInFuture return true if the iat is valid.

On OktaJWT.swift: is returning error when the iat is valid
Current code:
if OktaJWTVerifier.isIssuedInFuture(jwt.payload.issuedAt, leeway: self.validatorOptions["leeway"] as? Int) { throw OktaJWTVerificationError.IssuedInFuture }

Fixed Code:
if **!**OktaJWTVerifier.isIssuedInFuture(jwt.payload.issuedAt, leeway: self.validatorOptions["leeway"] as? Int) { throw OktaJWTVerificationError.IssuedInFuture }

Pass additional parameters to browser sign-in

Some developers need to pass additional parameters to the /authorize route (browser sign-in), such as:

  • A login hint (the login_hint parameter, string)
  • A state value (string)
  • Any string name/value pair

Unlike values like issuer and scopes, these parameters will not be stored in Okta.plist. We should make it possible to pass parameters to the browser sign-in method.

Mac support

How can I get the Okta SDK to work on mac? The current pod 'OktaAuth' is not compatible with OS X.

"(OS X 10.10) is not compatible with OktaAuth (0.1.0), which does not support osx."

The client secret is not send

On the class OktaAuth.swift, method authCodeFlow, when create the OIDAuthorizationRequest is not added the clientSecret.

To fix it, you have to get it:
let clientSecret = config["clientSecret"]

and then:
OIDAuthorizationRequest(configuration: oidConfig,
clientId: clientId,
clientSecret: clientSecret,
scopes: Utils.scrubScopes(config["scopes"]),.....

Token refreshing crashes after token expires

Copied from the devForum:

When calling isAuthenticated method, it is crashing at

guard let previousState = NSKeyedUnarchiver
.unarchiveObject(with: encodedAuthState.value) as? OktaTokenManager else { return false }

It seems to crash when access token is expired because whenever I call the method after fresh install, get access token, it works well. However after an hour (that’s when our token expires), it crashes. Only way to get around is to reinstall the app which means this SDK cant be used at all.

Force login

When AppAuth supports logout, we'll support it in this library (#7). In the mean time, it would be useful to have the option to forcibly ignore whether the user already has a session on the server (adding the prompt=login parameter on the /authorize request).

We should add a boolean forceLogin parameter to the login() method.

Native sign-in method

The SDK should provide a method to easily do the flow described in #78.

First, a Swift client for the Authentication API needs to be created. This work will be done in okta-auth-swift (see #81).

Then, this library must expose a method to start a sign-in request and pass the username/password directly. We will deprecate the existing login(username: string, password: string) method. This method will kick off the flow described in #78. This will result in one of two things:

  1. Login was valid and resulted in tokens. Like the existing login method, this should automatically store the tokens. Allow the developer to segue to a new view.
  2. The transaction response did not contain status SUCCESS, or some other error occurred (e.g., network error). Allow the developer to access the error object, or handle the status.

The result is that a developer can build their own native sign-in UI, use this new method to perform the sign-in flow (with no browser popup), and store tokens on the device.

Add `idp=` parameter support for AppAuth

As a developer, I want to trigger Okta to log in the user with Google using the idp parameter with app auth, so my user doesn't need to view a page to just click on another button

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.