NAV
Web Swift (iOS/macOS/tvOS/visionOS) Android

Introduction

Welcome to SnapAuth!

This documentation is for our Client SDKs. You can browse our Server API documentation here.

Client SDKs are used to start browser/device-native WebAuthn flows. They return one-time-use tokens that you send to your backend to use with the Server APIs.

Setup

Installation

// Node
npm i --save '@snapauth/sdk'
// UMD
<script src="https://unpkg.com/@snapauth/sdk"></script>
XCode > File > Add Package Dependencies...

https://github.com/snapauthapp/sdk-swift
// Coming soon!

Client code should use the official SDKs, available from the platform's package manager.

We strictly follow semantic versioning, so you can upgrade confidently within a major version. It's strongly recommended to keep your SDK(s) up to date.

SDK Setup

// npm
import { SDK } from '@snapauth/sdk'
const snapAuth = new SDK('pubkey_xxxx')
// UMD
const snapAuth = new SnapAuth.SDK('pubkey_xxxx')
import SnapAuth

let snapAuth = SnapAuth(publishableKey: "pubkey_xxxx")
// Coming soon!

Client SDKs will use your publishable API key. You may safely embed it in whatever way is most convenient for you.

The publishable key is specific to an environment - i.e. a domain. This is a requirement for the WebAuthn protocol - Credentials are bound to a specific domain.

Registration

let name: string // Some value from your app. The user will see this during sign-in.

const registration = await snapAuth.startRegister({ name })
if (registration.ok) {
  const token = registration.data.token
  // Send token to your backend along with other relevant data
} else {
  // If desired, inspect registration.error and decide how to proceed
}
// Tip: this needs to be in an `async` context. You can wrap this entire block
// in Task { ... } if you don't have one.
let result = await snapAuth.startRegister(name: "User's name")
switch result {
case .success(let registration):
  // Send registration.token to your backend
case .failure(let error):
  // If desired, inspect error and decide how to proceed
}
// Coming soon!

Wrapped Response (registration.data)

{
  "token": string,
  "expiresAt": Timestamp,
}

Registration is the process of creating a Credential for a User Account.

Users can have multiple Credentials, and each one must be registered independently. To start the process of creating a Credential, use the SDK's startRegister method. On success, it will return a registration token - this is a one-time-use token which you must send to your backend to attach to the user.

Request

Field Type Required? Usage
name string yes Name for the user. This is for client-side display; it is not sent to or retained by us.
displayName string no Display name for the user. Defaults to the value of name. Note: browser sign-in tends to display name and ignore displayName

Response

Field Type Meaning
token string The one-time-use token to send to your server to finish credential registration
expiresAt Timestamp When the token will expire.

Authentication

// Note: use either id or handle, not both.
let id: string|null
let handle: string|null

const auth = await snapAuth.startAuth({ id, handle })
if (auth.ok) {
  const token = auth.data.token
  // Send token to your backend along with other relevant data
} else {
  // If desired, inspect auth.error and decide how to proceed
}
// Tip: this needs to be in an `async` context. You can wrap this entire block
// in Task { ... } if you don't have one.
let result = await snapAuth.startAuth(.handle("Username"))
// Or snapAuth.startAuth(.id(userId))
switch result {
case .success(let auth):
  // Send auth.token to your backend
case .failure(let error):
  // If desired, inspect error and decide how to proceed
}
// Coming soon!

Wrapped Response (auth.data)

{
  "token": string,
  "expiresAt": Timestamp,
}

Authentication is the process of using a previously-registered credential. This may be to sign in to your application, or to elevate permissions for a sensitive action.

Like Registration, this API will return a one-time-use token which you must send to your backend to verify.

Request

Field Type Required? Usage
id string no* Your stable identifier for the user
handle string no * Your handle for the user (e.g. username)

Response

Field Type Meaning
token string The one-time-use token to send to your server to verify
expiresAt Timestamp When the token will expire.

* You must provide either id or handle. If you provide both, only id will be used.

Autofill-assisted requests

import { AuthResponse } from '@snapauth/sdk'

const auth = await snapAuth.autofill()
if (auth.ok) {
  const token = auth.data.token
  // e.g.
  const response = await postToYourBackend('/endpoint', { token })
  // .. Do whatever you need to!
} else {
  // Typically, autofill failures are safe to ignore
}

// On the page, you must also have a webauthn input:

<input type="text" autocomplete="username webauthn" />
// CAUTION: we've found the passkey AutoFill experience to be somewhat
// unreliable on supported Apple platforms.  We've filed issues to get this fixed.

// Your UI must be displaying a TextField with `textContentType` of `.username`

import SnapAuth

struct MyView: View {
  let snapAuth = SnapAuth(publishableKey: "pubkey_xxxx")
  var body: some View {
    TextField("Username")
      .textContentType(.username)
      .onAppear(perform: autoFill)
  }

  func autoFill() {
    Task {
      let autoFillResult = await snapAuth.handleAutoFill()
      guard case .success(let authn) = autoFillResult else {
        // Typically, autoFill failures are ok to ignore
        return
      }
      // Send authn.token to your backend for verification
    }
  }
}
// Coming soon!

For devices and platforms that support it, you can set up autofill-assisted requests. This will prompt the user to authenticate without having to type anything in - they only have to approve the action.

There are two setup steps:

Different platforms handle autofill "failures" in various ways. This includes autofill failing due to a foreground request starting, platform unavailability, or various other reasons.

Tips

SDK Design

const result = await snapAuth.someAction(...)
// result has an `errors` property, containing 0 or more errors
if (result.ok) {
  // result has a `data` property, which contains the documented response
} else {
  // `errors` is guaranteed to have at least one entry
}
let result = await snapAuth.someAction(...)
switch result {
case .success(let data):
  // data is the documented response format as a platform-native Struct
case .failure(let error):
  // Look at the error code and decide how to proceed
}
// Coming soon!

We aim to keep our SDKs as platform-native as possible. As such, we do not auto-generate SDKs from API definitions. Our documentation tooling doesn't perfectly support some of the subtle platform-specific differences - we're working on improving this!

The SDKs are designed so that following the "happy path" will be most reliable. We also focus on type safety so that you can leverage the tooling you're already familiar with. Responses use a Result type (natively, where it exists) to indicate success or failure.

You should never need to run SnapAuth Client SDKs with try/catch blocks.

Token Exchange

The Client SDKs return a one-time-use token, which you must be sent to your backend for further use. These tokens are exchanged with our Server SDKs to complete the registration and authentication processes.

Defensive Coding

Results may contain errors even if they are ok. These could hint at an outdated SDK, incorrect usage, deprecation, or something else.

Browser Usage

Browsers require the WebAuthn APIs to be used only in response to a user gesture, such as onClick or onSubmit.

Native apps tend to not have this restriction, but it's a good idea to avoid surprising your users!

API Format

Types

Timestamp

integer: Unix Timestamp, in seconds

Our Swift SDK automatically translates this to a native Date object.

Error

object: Information about an error or warning

Field Type Meaning
code string A machine-readable code. See below
message string A human-readable description of the error. This is intended primary for developers, not end-users

Errors

Code Meaning
timeout The user did not register or authenticate quickly enough
network_error There was a connection error between the client and SnapAuth
bad_request An invalid request was made. Usually this is a missing or invalid field
server_error Something went wrong our end. Please try again momentarily
canceled_by_user The user canceled the registration or authentication request
invalid_domain You are trying to perform a request on a domain that doesn't match the API key; OR you're trying to run on a non-HTTPS page
unexpected An unexpected error occurred. Please contact us for help!