A simple OAuth library for iOS with a built-in set of providers

Overview

Travis Status CocoaPods compatible Carthage compatible

SwiftyOAuth is a small OAuth library with a built-in set of providers and a nice API to add your owns.

let instagram: Provider = .instagram(clientID: "***", redirectURL: "foo://callback")

instagram.authorize { result in
    print(result) // success(Token(accessToken: "abc123"))
}

UsageProvidersInstallationLicense

Usage

Provider

Provider.swift

Step 1: Create a provider

Initialize a provider with the custom URL scheme that you defined:

// Provider using the server-side (explicit) flow

let provider = Provider(
    clientID:     "***",
    clientSecret: "***",
    authorizeURL: "https://example.com/authorize",
    tokenURL:     "https://example.com/authorize/token",
    redirectURL:  "foo://callback"
)

// Provider using the client-side (implicit) flow

let provider = Provider(
    clientID:     "***",
    authorizeURL: "https://example.com/authorize",
    redirectURL:  "foo://callback"
)

// Provider using the client-credentials flow

let provider = Provider(
    clientID:     "***",
    clientSecret: "***"
)

Alternatively, you can use one of the built-in providers:

let github = .gitHub(
    clientID:     "***",
    clientSecret: "***",
    redirectURL:  "foo://callback"
)

Optionally set the state and scopes properties:

github.state  = "asdfjkl;" // An random string used to protect against CSRF attacks.
github.scopes = ["user", "repo"]

Use a WKWebView if the provider doesn't support custom URL schemes as redirect URLs.

let provider = Provider(
    clientID:     "***",
    clientSecret: "***",
    authorizeURL: "https://example.com/authorize",
    tokenURL:     "https://example.com/authorize/token",
    redirectURL:  "https://an-arbitrary-redirect-url/redirect"
)

provider.useWebView = true

Define additional parameters for the authorization request or the token request with additionalAuthRequestParams and additionalTokenRequestParams respectively:

github.additionalAuthRequestParams["allow_signup"] = "false"
Step 2: Handle the incoming requests

Handle the incoming requests in your AppDelegate:

func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {
    github.handleURL(url, options: options)

    return true
}
Step 3: Ask for authorization

Finally, ask for authorization. SwiftyOAuth will either present a SFSafariViewController (iOS 9) or open mobile safari.

github.authorize { (result: Result<Token, Error>) -> Void in
    switch result {
    case .success(let token): print(token)
    case .failure(let error): print(error)
    }
}

If the provider provides an expirable token, you may want to refresh it.

let uber: Provider = .uber(
    clientID: "***",
    clientSecret: "***",
    redirectURL: "foo://callback/uber"
)

// uber.token!.isExpired => true

uber.refreshToken { result in
    switch result {
    case .success(let token): print(token)
    case .failure(let error): print(error)
    }
}

Token

Token.swift

The access_token, token_type, scopes, and informations related to the expiration are available as Token properties:

token.accessToken // abc123
token.tokenType   // .Bearer
token.scopes      // ["user", "repo"]

token.expiresIn // 123
token.isExpired // false
token.isValid   // true

Additionally, you can access all the token data via the dictionary property:

token.dictionary // ["access_token": "abc123", "token_type": "bearer", "scope": "user repo"]

Token Store

Every Token is stored and retrieved through an object that conforms to the TokenStore protocol.

The library currently supports following TokenStores:

provider.tokenStore = Keychain.shared

Keychain: Before you use thisTokenStore, make sure you turn on the Keychain Sharing capability.

provider.tokenStore = UserDefault.standard

UserDefaults: the default TokenStore. Information are saved locally and, if properly initialized, to your App Group.

provider.tokenStore = NSUbiquitousKeyValueStore.default

NSUbiquitousKeyValueStore: the information are saved in the iCloud Key Value Store. Before you use this TokenStore make sure your project has been properly configured as described here.

Error

Error.swift

Error is a enum that conforms to the ErrorType protocol.

  • cancel The user cancelled the authorization process by closing the web browser window.

  • applicationSuspended The OAuth application you set up has been suspended.

  • redirectURIMismatch The provided redirectURL that doesn't match what you've registered with your application.

  • accessDenied The user rejects access to your application.

  • invalidClient The clientID and or clientSecret you passed are incorrect.

  • invalidGrant The verification code you passed is incorrect, expired, or doesn't match what you received in the first request for authorization.

  • other The application emitted a response in the form of {"error": "xxx", "error_description": "yyy"} but SwiftyOAuth doesn't have a enum for it. The data is available in the associated values.

  • unknown The application emitted a response that is neither in the form of a success one ({"access_token": "xxx"...}) nor in the form of a failure one ({"error": "xxx"...}). The data is available in the associated value.

  • nsError An error triggered when making network requests or parsing JSON. The data is available in the associated value.

Providers

Providers/

Check the wiki for more informations!

Installation

Carthage

Carthage is a decentralized dependency manager that automates the process of adding frameworks to your Cocoa application.

You can install Carthage with Homebrew using the following command:

$ brew update
$ brew install carthage

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

github "delba/SwiftyOAuth" >= 1.1

CocoaPods

CocoaPods is a dependency manager for Cocoa projects.

You can install it with the following command:

$ gem install cocoapods

To integrate SwiftyOAuth into your Xcode project using CocoaPods, specify it in your Podfile:

use_frameworks!

pod 'SwiftyOAuth', '~> 1.1'

License

Copyright (c) 2016-2019 Damien (http://delba.io)

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

Comments
  • Authentication with Google: not matching redirect URL

    Authentication with Google: not matching redirect URL

    I was trying to perform a login with Google Service.

    Hereby the executed code

    
    let provider = Provider.Google(clientID: "$(the_client_id)", clientSecret: "$(the_client_secret)", redirectURL: "$(bundle_identifier):/urn:ietf:wg:oauth:2.0:oob")
    
    provider.scopes = ["https://www.googleapis.com/auth/analytics.readonly"]
    
    provider.authorize(self) { (result) in
        switch result {
        case .Success(let token):
            print(token)
        case .Failure(let error):
            print(error)
    }
    

    When the authorisation is granted in the Safari View Controller the redirect URL gets triggered with following format:

    $(bundle_identifier):/urn:ietf:wg:oauth:2.0:oob?code=$(the_authorization_code)
    

    This cause an issue for when the library checks if the redirect URL use during the initialisation of the Provider matches the received redirect URL from the AppDelegate.

    I've tried other combination of redirect URL but that's the redirect URL format that the Google guide advocates.

    Did anyone experienced this when trying the built in Google Provider?

    I think an easy fix would be to match the retrieved URL by removing the GET parameter from the URL but before open a new PR I'd like to receive some feedback about this.

    opened by fabiomassimo 34
  • Multi platform support

    Multi platform support

    The OAuth Authentication process nowadays can be triggered from many devices equipped with different os: watch OS, iOS, tvOS.

    Unfortunately, not all of this operating system can rely on a safe way to implement the OAuth 2.0 authentication flow:

    • tvOS does not support SafariServices or Webkit.
    • watchOS does not support SafariServices or Webkit.
    • Today extension can not present webpages.

    My idea to address this issue would be to implement for SwiftyOAuth following goals:

    • [ ] Make the library use app extension API only.
    • [ ] Add support for multiple platform: iOS, watchOS, tvOS.
    • [ ] Improve -authorize method depending on current platform and capabilities.

    What do you think?

    opened by fabiomassimo 10
  • Issue in following the README for handling incoming requests in the AppDelegate

    Issue in following the README for handling incoming requests in the AppDelegate

    From the docs:

    Step 2: Handle the incoming requests
    
    Handle the incoming requests in your AppDelegate:
    
    func application(app: UIApplication, openURL url: NSURL, options: [String : AnyObject]) -> Bool {
        github.handleURL(url, options: options)
    
        return true
    }
    

    Unfortunately, while I was following the README, I found out that that the delegate method signature is slightly different:

    func application(application: UIApplication, openURL url: NSURL, sourceApplication: String?, annotation: AnyObject) -> Bool
    

    This causes an inconsistency with the designated method to handle an URL from the Provider.

        /**
         Handles the incoming URL.
    
         - parameter URL:     The incoming URL to handle.
         - parameter options: A dictionary of launch options.
         */
        public func handleURL(URL: NSURL, options: [String : AnyObject])
    

    I think it should be rewritten in something like:

    public func handleURL(URL: NSURL, sourceApplication: String?) 
    

    Such that the Step 2 from the README would look like:

    func application(application: UIApplication, openURL url: NSURL, sourceApplication: String?, annotation: AnyObject) -> Bool {
        github.handleURL(url, sourceApplication: sourceApplication)
    
        return true
    }
    
    opened by fabiomassimo 7
  • Instagram does not supply token_type and the flow breaks

    Instagram does not supply token_type and the flow breaks

    In Token.swift, this init makes the all 3 parameters mandatory:

            guard let
                accessToken = json["access_token"] as? String,
                tokenType = json["token_type"] as? String,
                scope = json["scope"] as? String
            else { return nil }
    

    However, Instagram only returns access_token

    {
        "access_token": "2342264381.bc3c943.6086017a221b427a997e4928f0ea197b",
        "user": {
    ...
        }
    }
    

    What do you think about this:

        internal init?(json: JSON) {
            guard let
                accessToken = json["access_token"] as? String
            else { return nil }
    
            self.accessToken = accessToken
    
            self.tokenType = json["token_type"] as? String ?? ""
            self.scope = json["scope"] as? String ?? ""
    
            self.dictionary = json
        }
    
    opened by radianttap 7
  • Authenticate NSURLRequest

    Authenticate NSURLRequest

    Summary

    Authenticate NSURLRequest as specified by OAuth 2.0 guidelines for token type Bearer.

    The Provider exposes a convenience method that, in case the available token is expired, refreshes the token and then uses it to authenticate any NSURLRequest.

    Why

    This feature give to the client an easy way to integrate a valid access token, retrieved via OAuth 2.0, in any NSURLRequest that the client might have created beforehand.

    Note

    To improve test cases accuracy I needed to add a dependency for the test target: OHTTPStubs.

    I found the best way to do it via Carthage. To get started run the shell script in the bin folder.

    opened by fabiomassimo 5
  • Created `TokenStore` protocol for storing `Token` type

    Created `TokenStore` protocol for storing `Token` type

    Summary

    Abstracted the logic for storing and retrieving a Token to a protocol, such that any object that conforms to it can be used to store and retrieve a Token type.

    Why

    By abstracting the implementation of the logic responsible to store/retrieve an object to a protocol, the user's of the library can provide his own [..]TokenStore that better fits his needs.

    i.e.: this feature made possible to support iCloud Key Value Store very easily by gaining the opportunity to store a Token in the iCloud Key Value Store Container.

    Note

    As proof of concept I've implemented this protocol to support NSUserDefaults and NSUbiquitousKeyValueStore.

    opened by fabiomassimo 5
  • Swift 3.0

    Swift 3.0

    Summary

    Implementation for #13

    • [x] Add new grant type: http://oauth.net/grant_type/device/1.0
    • [x] Handle new error cases: "authorisation_pending" , "slow_down", "code_expired"
    • [x] Extend the Provider with support to request an access token with new grant type.
    opened by fabiomassimo 4
  • Topic token dictionary

    Topic token dictionary

    When storing the existing Token, it already has proper created_at value. When restoring back using init(dictionary:) that original value should not be over-written.

    opened by radianttap 3
  • Keychain token store

    Keychain token store

    As requested, keychain support should not be based on third-party libraries, but uses a small wrapper found at https://gist.github.com/jackreichert/414623731241c95f0e20

    Hint: func setToken() should return a Bool value, but has to be changed at protocol level (TokenStore).

    opened by johannwilfling 3
  • Improved feature for `Error` enum struct

    Improved feature for `Error` enum struct

    Summary

    Improved initialisation and features provided by the Error enum struct in order to provide a better error handling in the library

    Why

    Currently there are few places in the code marked with a TODO about a better error handling. I hope this will help.

    opened by fabiomassimo 3
  • How to resolve view is not in window hierarchy error?

    How to resolve view is not in window hierarchy error?

    Attempt to present <SFSafariViewController: 0x7fc7ba018400> on <MyOauth.ViewController: 0x7fc7b860b070> whose view is not in the window hierarchy!

    opened by udayathreya 1
  • Topic self signed

    Topic self signed

    I hate to re-invent hot water so I picked up the Server Trust handling from Alamofire.

    Added Extension to URLSession to pick up current serverTrustPolicy from HTTPConfig struct, which is public and can be set from any other module.

    opened by radianttap 2
  • Support OAuth 2.0 Device Flow

    Support OAuth 2.0 Device Flow

    Device flow's goal is to implement OAuth 2.0 authorisation flow on devices with limited capabilities (i.e. no WebKit).

    In my overview to support this:

    • [ ] Add new grant type: http://oauth.net/grant_type/device/1.0
    • [ ] Handle new error cases: "authorisation_pending" , "slow_down", "code_expired"
    • [ ] Extend the Provider with support to request an access token with new grant type.
    opened by fabiomassimo 12
Releases(v0.3)
  • v0.3(May 26, 2016)

    Refresh the tokens:

    provider.refreshToken { result in
        // ...
    }
    

    Check if a token is valid:

    if let token = provider.token {
        print(token.isValid)
        print(token.isExpired)
    }
    

    Optionally set the scopes:

    provider.scopes = ["some", "scope", "here"]
    

    Optionally set the additional parameters for the authorization/token requests:

    provider.additionalAuthRequestParams
    provider.additionalTokenRequestParams
    

    A new wiki 😃

    Source code(tar.gz)
    Source code(zip)
Owner
Damien
Damien
Swift based OAuth library for iOS

OAuthSwift Swift based OAuth library for iOS and macOS. Support OAuth1.0, OAuth2.0 Twitter, Flickr, Github, Instagram, Foursquare, Fitbit, Withings, L

OAuthSwift 3.1k Jan 3, 2023
Swift based OAuth library for iOS and macOS

OAuthSwift Swift based OAuth library for iOS and macOS. Support OAuth1.0, OAuth2.0 Twitter, Flickr, Github, Instagram, Foursquare, Fitbit, Withings, L

OAuthSwift 3.1k Jan 3, 2023
A simple to use, standard interface for authenticating to oauth 2.0 protected endpoints via SFSafariViewController.

AuthenticationViewController A simple to use, standard interface for authenticating to OAuth 2.0 protected endpoints via SFSafariViewController. Instr

Raul Riera 256 Dec 14, 2022
Swift async/await OAuth 2.0 HTTP request library.

SwAuth SwAuth is an OAuth 2.0 HTTP request library written in Swift iOS 15.0+, macOS 12.0+, watchOS 8.0+, and tvOS 15.0+. Features Requirements Instal

Colaski 17 Nov 5, 2022
A simple library to make authenticating tvOS apps easy via their iOS counterparts.

Voucher The new Apple TV is amazing but the keyboard input leaves a lot to be desired. Instead of making your users type credentials into their TV, yo

Riz 516 Nov 24, 2022
FCLAuthSwift is a Swift library for the Flow Client Library (FCL) that enables Flow wallet authentication on iOS devices.

FCLAuthSwift is a Swift library for the Flow Client Library (FCL) that enables Flow wallet authentication on iOS devices. Demo The demo a

Zed 3 May 2, 2022
Simple OAuth2 library with a support of multiple services.

Simple OAuth2 library with a support of multiple services.

HyperRedink 68 May 13, 2022
Example of simple OAuth2 authentication using Alamofire 5 and RxSwift library

REST Client based on Alamofire 5 and RxSwift library. Supports OAuth2 and Basic authentication interceptor.

Tomáš Smolík 3 Dec 8, 2022
A simple way to implement Facebook and Google login in your iOS apps.

Simplicity Simplicity is a simple way to implement Facebook and Google login in your iOS apps. Simplicity can be easily extended to support other exte

Simplicity Mobile 681 Dec 18, 2022
A simple project for Face ID Authentication for iOS device using LocalAuthentication Framework

BiometricAuthentication This respository is a simple project for Face ID Authentication for iOS device using LocalAuthentication Framework and infoPli

Lee McCormick 0 Oct 23, 2021
LinkedInSignIn - Simple view controller to log in and retrieve an access token from LinkedIn.

LinkedInSignIn Example To run the example project, clone the repo, and run pod install from the Example directory first. Also you need to setup app on

Serhii Londar 34 Sep 1, 2022
A quick and simple way to authenticate an Instagram user in your iPhone or iPad app.

InstagramSimpleOAuth A quick and simple way to authenticate an Instagram user in your iPhone or iPad app. Adding InstagramSimpleOAuth to your project

Ryan Baumbach 90 Aug 20, 2022
A quick and simple way to authenticate a Dropbox user in your iPhone or iPad app.

DropboxSimpleOAuth A quick and simple way to authenticate a Dropbox user in your iPhone or iPad app. Adding DropboxSimpleOAuth to your project CocoaPo

Ryan Baumbach 42 Dec 29, 2021
A quick and simple way to authenticate a Box user in your iPhone or iPad app.

BoxSimpleOAuth A quick and simple way to authenticate a Box user in your iPhone or iPad app. Adding BoxSimpleOAuth to your project CocoaPods CocoaPods

Ryan Baumbach 15 Mar 10, 2021
InstagramLogin allows iOS developers to authenticate users by their Instagram accounts.

InstagramLogin handles all the Instagram authentication process by showing a custom UIViewController with the login page and returning an access token that can be used to request data from Instagram.

Ander Goig 67 Aug 20, 2022
OAuth2 framework for macOS and iOS, written in Swift.

OAuth2 OAuth2 frameworks for macOS, iOS and tvOS written in Swift 5.0. ⤵️ Installation ?? Usage ?? Sample macOS app (with data loader examples) ?? Tec

Pascal Pfiffner 1.1k Jan 2, 2023
SimpleAuth is designed to do the hard work of social account login on iOS

SimpleAuth is designed to do the hard work of social account login on iOS. It has a small set of public APIs backed by a set of "providers"

Caleb Davenport 1.2k Nov 17, 2022
Krypton turns your iOS device into a WebAuthn/U2F Authenticator: strong, unphishable 2FA.

Krypton turns your iOS device into a WebAuthn/U2F Authenticator: strong, unphishable 2FA. Krypton implements the standardized FIDO Universal 2nd Facto

krypt.co 332 Nov 5, 2022
A simple OAuth library for iOS with a built-in set of providers

SwiftyOAuth is a small OAuth library with a built-in set of providers and a nice API to add your owns. let instagram: Provider = .instagram(clientID:

Damien 477 Oct 15, 2022
Postal is a swift framework providing simple access to common email providers.

Postal is a swift framework providing simple access to common email providers. Example Connect let postal = Postal(configuration: .icloud(login: "myem

Snips 644 Dec 23, 2022