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

extend AuthCognitoTokens to provide more functionality #3288

Closed
drmarkpowell opened this issue Oct 10, 2023 · 3 comments
Closed

extend AuthCognitoTokens to provide more functionality #3288

drmarkpowell opened this issue Oct 10, 2023 · 3 comments
Labels
auth Issues related to the Auth category question General question

Comments

@drmarkpowell
Copy link

drmarkpowell commented Oct 10, 2023

Is your feature request related to a problem? Please describe.

I have two recurring problems I'd love to be able to solve (at all).

One, I know of no way to know when a refresh token is invalid. When this happens, the app login flow will generate an error and we have to handle that properly. There is no way I know of to mock this for testing, and no way I know of to reproduce it by injecting an expired token or mock token in order to validate that the application logic that handle the error and navigate the user to the login page works properly. I'm looking for a way to query the token provider, to ask it "Is the refresh token expired?"

Two, I know of no way to completely delete tokens when the user signs out, which I want to do to make a signout application logic actually thorough, requiring the user to sign in again the next time they mean to access the app. I know of no way to delete the current access and refresh tokens from the secure storage where they are kept.

Describe the solution you'd like

Here is the current API:

public protocol AuthCognitoTokensProvider {
    func getCognitoTokens() -> Result<AuthCognitoTokens, AuthError>
}

public protocol AuthCognitoTokens {

    var idToken: String {get}

    var accessToken: String {get}

    var refreshToken: String {get}

}

I would like to see something added to the API similar to:

public protocol AuthCognitoTokens{ ...
   func isRefreshTokenExpired() -> Bool // return true if the refresh token is expired, else false
   fund deleteTokens() // remove the current access and refresh token information from memory and secure storage

Describe alternatives you've considered

I've tried using Foundation API to clear secure keychain tokens, but it isn't working.
I've considered storing the date/time of refresh token generation in UserDefaults or similar and tracking it within the app, but that's error prone and shouldn't be implemented by third party developers...it should be part of Amplify SDK.

Is the feature request related to any of the existing Amplify categories?

Auth

Additional context

No response

@atierian atierian added auth Issues related to the Auth category feature-request Request a new feature labels Oct 10, 2023
@atierian
Copy link
Member

atierian commented Oct 10, 2023

Hi @drmarkpowell, thanks for opening this issue.

First question - how to know when a refresh token is invalid:

Do you need to know if the refresh token has expired, or would knowing if the user is currently signed in suffice?
If the latter, you can check this easily with:

let isSignedIn = try await Amplify.Auth.fetchAuthSession().isSignedIn

For test mocks, the likely easiest way is injecting the calls to Amplify in something that you can swap out in your tests.
Here's a very simplified example:

struct Router {
  let signedInResolver: () async throws -> Bool

  func userRoute() async -> Route {
    do {
      let isUserSignedIn = try await signedInResolver()
      return isUserSignedIn ? .profile : .login
    } catch {
        return .error(error)
    }
  }
}

extension Router {
  static let live = Router(
    signedInResolver: {
      try await Amplify.Auth.fetchAuthSession().isSignedIn
    }
  )
}

// Application Target
 let route = await Router.live.userRoute()

// Test Target
let route = await Router(signedInResolver: { true }).userRoute()
// assert ProfileRoute

let route = await Router(signedInResolver: { false }).userRoute()
// assert LoginRoute

let route = await Router(signedInResolver: { throw SomeError() }).userRoute()
// assert ErrorRoute

Second question - how to completely delete tokens when the user signs out:

This is done automatically by Amplify. Are you seeing behavior that indicates otherwise?

@atierian atierian added question General question and removed feature-request Request a new feature labels Oct 10, 2023
@aws-amplify aws-amplify deleted a comment from github-actions bot Oct 10, 2023
@atierian atierian added pending-community-response Issue is pending response from the issue requestor closing soon This issue will be closed in 7 days unless further comments are made. labels Oct 10, 2023
@drmarkpowell
Copy link
Author

drmarkpowell commented Oct 16, 2023 via email

@atierian atierian removed pending-community-response Issue is pending response from the issue requestor closing soon This issue will be closed in 7 days unless further comments are made. labels Oct 16, 2023
@atierian
Copy link
Member

atierian commented Oct 16, 2023

IsSignedIn would not give me that, if I understand correctly.

That's correct, isSignedIn by itself won't tell you if you the refresh token has expired. For your use case, you can pass .forceRefresh() to fetchAuthSession(options:) - doing so will allow you to catch a .sessionExpired error if the refresh token is expired. For example:

do {
    // .forceRefresh() will refresh the access tokens
    // if the refresh token is expired, it will throw AuthError.sessionExpired
    let isSignedIn = try await Amplify.Auth.fetchAuthSession(
        options: .forceRefresh()
    ).isSignedIn

    // ...
} catch AuthError.sessionExpired {
    // the refresh token has expired
    // you need to call `signOut()` before attempting to sign in.
    _ = await Amplify.Auth.signOut()

    // now you can sign in
    // ...
} catch {}

@atierian atierian added the pending-community-response Issue is pending response from the issue requestor label Oct 16, 2023
@harsh62 harsh62 closed this as completed Nov 30, 2023
@github-actions github-actions bot removed the pending-community-response Issue is pending response from the issue requestor label Nov 30, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
auth Issues related to the Auth category question General question
Projects
None yet
Development

No branches or pull requests

3 participants