Use atproto actions with ease in iOS shortcuts
1//
2// GetServiceAuthIntent.swift
3// shortcut
4//
5// Created by Bailey Townsend on 7/23/25.
6//
7
8import ATProtoKit
9import AppIntents
10import SwiftData
11import SwiftUI
12
13struct GetServiceAuthIntent: AppIntent {
14
15 @Parameter(
16 title: "AT Identifier",
17 description:
18 "The saved AT Identifier of the account you want to use to authenticate with and create a JWT for",
19 requestValueDialog: IntentDialog("Choose a logged in AT Identifier"))
20 public var atIdentifier: AtIdentifierAppEntity
21
22 //TODO does not look to be working as expected
23 // @Parameter(
24 // title: "Expiration",
25 // description: "Time in seconds for the JWT to be valid. Default is 60")
26 // var exp: Int?
27
28 @Parameter(
29 title: "Lexicon XRPC Method",
30 description:
31 "This is the XRPC method you want to set in the JWT's claim. like neat.atprotocol.app.privateMessage. Allows for scoping with the external service. Not required",
32 default: nil)
33 var lxm: String?
34
35 static let title: LocalizedStringResource = "Create A Service Auth JWT"
36
37 static let description: IntentDescription =
38 "Creates a JWT that is signed by your accounts private key to allow you to authenticate with an external service proving you are the atprotocol account owner. This JWT is valid for 60 seconds from the time it is created"
39
40 static var parameterSummary: some ParameterSummary {
41 Summary("Create a JWT for \(\.$atIdentifier) to authenticate with an external service") {
42 // \.$exp
43 \.$lxm
44 }
45 }
46
47 func perform() async throws -> some ReturnsValue<String> {
48
49 do {
50
51 let atProtoManager = AtProtocolManager()
52 let tokenResponse = try await atProtoManager.getServiceAuth(
53 sessionId: self.atIdentifier.id, usersDid: self.atIdentifier.did, exp: nil,
54 lxm: self.lxm)
55
56 return .result(
57 value: tokenResponse.token)
58
59 } catch let shortCutError as ShortcutErrors {
60 switch shortCutError {
61 case .NoSession:
62 throw GenericIntentError.message("No session found")
63 case .ErrorCreatingARecord(let errorMessage):
64 throw GenericIntentError.message(errorMessage)
65 case .AuthError(let authError):
66 throw GenericIntentError.message(authError)
67 }
68 } catch let shortCutError as GenericIntentError {
69 throw shortCutError
70 } catch _ as DecodingError {
71 throw GenericIntentError.message(
72 "There was an error decoding the record. Please make sure your record is valid JSON or use a shortcut dictionary."
73 )
74 } catch {
75 throw GenericIntentError.general
76 }
77 }
78}