Advanced Networking with URLSession

Sep 15 2022 · Swift 5.6, iOS 15, Xcode 13.4.1

Part 2: Authentication, Cookies & App Transport Security

09. Understand Authentication

Episode complete

Play next episode

Next
About this episode

Leave a rating/review

See forum comments
Cinema mode Mark complete Download course materials
Previous episode: 08. Introduction Next episode: 10. Learn App Transport Security

Get immediate access to this and 4,000+ other videos and books.

Take your career further with a Kodeco Personal Plan. With unlimited access to over 40+ books and 4,000+ professional videos in a single subscription, it's simply the best investment you can make in your development career.

Learn more Already a subscriber? Sign in.

Heads up... You've reached locked video content where the transcript will be shown as obfuscated text.

If a session task requires authentication either as part of the requested URL or in the shared URL credential storage (and there are no valid credentials available) then the session creates an authentication challenge.

class AcronymSender {
  private let session: URLSession
  private let sessionConfiguration: URLSessionConfiguration
  
  init() {
    self.sessionConfiguration = URLSessionConfiguration.default
    self.sessionConfiguration.waitsForConnectivity = true
    self.session = URLSession(configuration: sessionConfiguration)
  }
}
private let baseURL: URL
private let loginEndpoint: URL
private let newEndpoint: URL
self.baseURL = URL(string: "https://tilftw.herokuapp.com/“)!
self.loginEndpoint = URL(string: "login", relativeTo: baseURL)!
self.newEndpoint = URL(string: "new", relativeTo: baseURL)!
func send(acronym: Acronym, for user: User) async throws {
    
}
enum AcronymError: Error {
  case failedToEncodeUserCredentials
}
let credentials = "\(user.email):\(user.password)"

guard let data = credentials.data(using: .utf8) else {
  throw AcronymError.failedToEncodeUserCredentials
}

let encodedString = data.base64EncodedString(options: Data.Base64EncodingOptions(rawValue: 0))
var loginRequest = URLRequest(url: loginEndpoint)
loginRequest.httpMethod = "POST"
loginRequest.allHTTPHeaderFields = [
  "accept": "application/json",
  "content-type": "application/json",
  "authorization": "Basic \(encodedString)"
]
let (loginData, loginResponse) = try await session.data(for: loginRequest)
guard let httpLoginResponse = loginResponse as? HTTPURLResponse,
      httpLoginResponse.statusCode == 200
else {
  throw AcronymError.invalidLoginResponse
}
case invalidLoginResponse
var auth = Auth(token: "")
    
do {
  auth = try JSONDecoder().decode(Auth.self, from: loginData)
} catch {
  throw AcronymError.failedToDecodeAuthToken
}
case failedToDecodeAuthToken
var acronymRequest = URLRequest(url: newEndpoint)
acronymRequest.httpMethod = "POST"
acronymRequest.allHTTPHeaderFields = [
  "accept": "application/json",
  "content-type": "application/json",
  "authorization": "Bearer \(auth.token)"
]
do {
  acronymRequest.httpBody = try JSONEncoder().encode(acronym)
} catch {
  throw AcronymError.failedToEncodeAcronym
}
case failedToEncodeAcronym
let (_, acronymResponse) = try await session.data(for: acronymRequest)
    
guard let httpAcronymResponse = acronymResponse as? HTTPURLResponse,
      httpAcronymResponse.statusCode == 200
else {
  throw AcronymError.invalidAcronymResponse
}
case invalidAcronymResponse
private let sender: AcronymSender = AcronymSender()
private let user: User = User(email: "jo@razeware.com", name: "jo", password: "password")
private func sendAcronymTapped() async {
  do {
    try await sender.send(acronym: acronym, for: user)
      
    Task { @MainActor in
      showAcronymSubmitSucceededAlert = true
    }
      
  } catch {
    Task { @MainActor in
      showAcronymSubmitFailedAlert = true
    }
  }
}
Task {
  await sendAcronymTapped()
}
https://tilftw.herokuapp.com/acronyms