Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor(docs): polish swift SDK content #718

Merged
merged 2 commits into from
Jun 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions docs/quick-starts/fragments/_configure-redirect-uri.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,3 @@
</p>

<img alt="Redirect URI in Logto Console" src={props.figureSrc} width="600px" />

[Redirect URI](https://www.oauth.com/oauth2-servers/redirect-uris/) is an OAuth 2.0 concept which implies the location should redirect after authentication.
8 changes: 2 additions & 6 deletions docs/quick-starts/fragments/_sign-in-note.mdx
Original file line number Diff line number Diff line change
@@ -1,8 +1,4 @@
:::note

<p>
Before calling <code>{props.calling}</code>, make sure you have correctly configured Redirect URI
in Admin Console.
</p>

Before calling <code>{props.calling}</code>, make sure you have correctly configured Redirect URI
in Admin Console.
:::
95 changes: 82 additions & 13 deletions docs/quick-starts/framework/swift/README.mdx
gao-sun marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -6,53 +6,121 @@ sidebar_custom_props:
---

import AppNote from '../../fragments/_app-note.mdx';
import Checkpoint from '../../fragments/_checkpoint-test-your-application.md';
import FindUserInfoMissing from '../../fragments/_find-user-info-missing.mdx';
import FurtherReadings from '../../fragments/_further-readings.md';
import GetUserInfoApis from '../../fragments/_get-user-info-apis.mdx';
import ScopesAndClaims from '../../fragments/_scopes-and-claims.mdx';
import ScopesAndClaimsIntroduction from '../../fragments/_scopes-claims-introduction.md';

import AddSdk from './_add-sdk.mdx';
import ImplementSignIn from './_implement-sign-in.mdx';
import ImplementSignInAndSignOut from './_implement-sign-in-and-sign-out.mdx';
import InitClient from './_init-client.mdx';
import ApiResources from './api-resources/_index.mdx';

# iOS: Integrate Logto Swift SDK
# Integrate Logto Swift SDK

<AppNote type="Native app" />

## Add Logto SDK as a dependency
## Installation

<AddSdk />

## Init `LogtoClient`
## Integration

### Init `LogtoClient`

<InitClient />

## Sign in
### Implement sign-in and sign-out

<ImplementSignInAndSignOut />

<Checkpoint />

## Fetch user information

### Display user information

To display the user's information, you can use the `client.getIdTokenClaims()` method. For example, in a SwiftUI app:

```swift title="ContentView.swift"
struct ContentView: View {
@State var isAuthenticated: Bool
@State var name: String?

init() {
isAuthenticated = client.isAuthenticated
name = try? client.getIdTokenClaims().name
}

var body: some View {
VStack {
if isAuthenticated {
Text("Welcome, \(name)")
} else {
Text("Please sign in")
}
}
}
}
```

### Request additional claims

<FindUserInfoMissing method="client.getIdTokenClaims()" />

<ScopesAndClaimsIntroduction />

<ImplementSignIn />
To request additional scopes, you can pass the scopes to the `LogtoConfig` object. For example:

## Sign out
```swift title="ContentView.swift"
let config = try? LogtoConfig(
endpoint: "<your-logto-endpoint>", // E.g. http://localhost:3001
appId: "<your-app-id>",
// highlight-start
scopes: [
UserScope.Email.rawValue,
UserScope.Phone.rawValue,
]
// highlight-end
)
```

Calling `.signOut()` will clean all the Logto data in Keychain, if it has.
Then you can access the additional claims in the return value of `client.getIdTokenClaims()`:

```swift
await client.signOut()
let claims = try? client.getIdTokenClaims()
// Now you can access additional claims `claims.email`, `claims.phone`, etc.
```

## Fetch user information
### Claims that need network requests

To prevent bloating the user object, some claims require network requests to fetch. For example, the `custom_data` claim is not included in the returned object even if it's requested in the scopes. To access these claims, you can use the `client.fetchUserInfo()` method:

```swift
let userInfo = try? client.fetchUserInfo()
// Now you can access the claim `userInfo.custom_data`
```

To learn more about the available scopes and claims, see the [Scopes and claims](#scopes-and-claims) section.

### Fetch user information manually

<GetUserInfoApis
fetchUserInfoApi="logtoClient.fetchUserInfo()"
getIdTokenClaimsApi="logtoClient.getIdTokenClaims()"
fetchUserInfoApi="client.fetchUserInfo()"
getIdTokenClaimsApi="client.getIdTokenClaims()"
/>

### Scopes and claims

<ScopesAndClaims />

## API resources

<ApiResources />

### Attach acess token to request headers
### Attach access token to request headers

Put the token in the `Authorization` field of HTTP headers with the Bearer format (`Bearer YOUR_TOKEN`), and you are good to go.

Expand All @@ -64,6 +132,7 @@ The Bearer Token's integration flow may vary based on the framework or requester
await LogtoRequest.get(
useSession: session,
endpoint: userInfoEndpoint,
// highlight-next-line
headers: ["Authorization": "Bearer \(accessToken)"]
)
```
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import redirectUriFigure from '../../assets/ios-redirect-uri.png';
import ConfigureRedirectUri from '../../fragments/_configure-redirect-uri.mdx';
import SignInNote from '../../fragments/_sign-in-note.mdx';
import SignInFlowSummary from '../../fragments/_web-sign-in-flow-summary.mdx';

<SignInFlowSummary />

#### Configure redirect URI

<ConfigureRedirectUri figureSrc={redirectUriFigure} redirectUri="io.logto://callback" />

:::info
The Redirect URI in iOS SDK is only for internal use. There's _NO NEED_ to add a [Custom URL Scheme](https://developer.apple.com/documentation/xcode/defining-a-custom-url-scheme-for-your-app) until a connector asks.
:::

#### Sign-in and sign-out

<SignInNote calling=".signInWithBrowser(redirectUri:)" />

You can use `client.signInWithBrowser(redirectUri:)` to sign in the user and `client.signOut()` to sign out the user.

For example, in a SwiftUI app:

```swift title="ContentView.swift"
struct ContentView: View {
@State var isAuthenticated: Bool

init() {
isAuthenticated = client.isAuthenticated
}

var body: some View {
VStack {
if isAuthenticated {
Button("Sign Out") {
Task { [self] in
await client.signOut()
isAuthenticated = false
}
}
} else {
Button("Sign In") {
Task { [self] in
do {
try await client.signInWithBrowser(redirectUri: "${
props.redirectUris[0] ?? 'io.logto://callback'
}")
isAuthenticated = true
} catch let error as LogtoClientErrors.SignIn {
// error occured during sign in
} catch {
// other errors
}
}
}
}
}
}
}
```
26 changes: 0 additions & 26 deletions docs/quick-starts/framework/swift/_implement-sign-in.mdx

This file was deleted.

8 changes: 7 additions & 1 deletion docs/quick-starts/framework/swift/_init-client.mdx
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
```swift
Initialize the client by creating a `LogtoClient` instance with a `LogtoConfig` object.

```swift title="ContentView.swift"
import Logto
import LogtoClient

Expand All @@ -9,6 +11,8 @@ let config = try? LogtoConfig(
let client = LogtoClient(useConfig: config)
```

:::info

By default, we store credentials like ID Token and Refresh Token in the Keychain. Thus the user doesn't need to sign in again when he returns.

To turn off this behavior, set `usingPersistStorage` to `false`:
Expand All @@ -19,3 +23,5 @@ let config = try? LogtoConfig(
usingPersistStorage: false
)
```

:::
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
```swift
```swift title="ContentView.swift"
let config = try? LogtoConfig(
endpoint: "<your-logto-endpoint>", // E.g. http://localhost:3001
appId: "<your-app-id>",
// highlight-next-line
resources: ["https://shopping.your-app.com/api", "https://store.your-app.com/api"], // Add API resources
)
let client = LogtoClient(useConfig: config)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
```swift
```swift title="ContentView.swift"
let config = try? LogtoConfig(
endpoint: "<your-logto-endpoint>",
appId: "<your-app-id>",
// highlight-start
scopes: ["shopping:read", "shopping:write", "store:read", "store:write"],
resources: ["https://shopping.your-app.com/api", "https://store.your-app.com/api"],
// highlight-end
)
let client = LogtoClient(useConfig: config)
```
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
```swift
```swift title="ContentView.swift"
let config = try? LogtoConfig(
endpoint: "<your-logto-endpoint>",
appId: "<your-app-id>",
// highlight-start
scopes: ["read", "write"],
resources: ["https://shopping.your-app.com/api", "https://store.your-app.com/api"],
// highlight-end
)
let client = LogtoClient(useConfig: config)
```
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
```swift
let accessToken = try await client.getAccessToken(for: "https://shopping.your-app.com/api")
// Custom logic
```swift title="ContentView.swift"
let accessToken = try await client.getAccessToken(for: "https://shopping.your-app.com/api")
```
4 changes: 2 additions & 2 deletions tutorial/build-with-logto/_integrate-sdk-ios-swift.mdx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import AddSdk from '../../docs/quick-starts/framework/swift/_add-sdk.mdx';
import ImplementSignIn from '../../docs/quick-starts/framework/swift/_implement-sign-in.mdx';
import ImplementSignInAndSignOut from '../../docs/quick-starts/framework/swift/_implement-sign-in-and-sign-out.mdx';
import InitClient from '../../docs/quick-starts/framework/swift/_init-client.mdx';

import TestYourIntegration from './fragments/_test-your-integration.mdx';
Expand All @@ -14,6 +14,6 @@ import TestYourIntegration from './fragments/_test-your-integration.mdx';

### Sign in

<ImplementSignIn />
<ImplementSignInAndSignOut />

<TestYourIntegration sdk="iOS" />
Loading