Skip to content

401 Unauthorized Errors Due to missing token in Amplify iOS SDK (Version 2.33.6) #3926

@jerfranco-deloitte

Description

@jerfranco-deloitte

Describe the bug

We are experiencing intermittent 401 Unauthorized errors in our iOS app using AWS Amplify SDK version 2.33.6. The issue seems to be affecting some users but not all, and we have been unable to replicate the problem internally. The errors appear to be related to missing or invalid tokens, with most server logs indicating missing tokens as the primary cause.

Steps To Reproduce

1. Implement authentication using AWS Amplify and Cognito in an iOS app.
2. Use the fetchAuthSession() method to get tokens which will be use as bearer token for api endpoints.
3. After some time, observe that API requests result in 401 errors due to expired tokens.

Additional note:
One user reported that he/she encountered this issue right after updating the myVicroads app to the latest version. However, the user also said he/she hadn't logged in for a while before updating the app.

Expected behavior

The fetchAuthSession() method should automatically refresh expired tokens or provide valid tokens, preventing 401 errors due to missing or invalid tokens.

Amplify Framework Version

2.33.6

Amplify Categories

Auth

Dependency manager

Swift PM

Swift version

5

CLI version

2

Xcode version

16.1

Relevant log output

<details>
<summary>Log Messages</summary>

Invalid tokens

2024-11-28T00:41:51.994Z  b6d1358e-928f-4e93-bd74-d432af989c25  trce  [Information] Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler: Bearer was not authenticated. Failure message: IDX10223: Lifetime validation failed. The token is expired. ValidTo: 'System.DateTime', Current time: 'System.DateTime'.

2024-11-28T00:42:16.660Z  b4e2bc2f-f221-47a9-95b7-364a8b2e949f  trce  [Information] Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler: Failed to validate the token.

Missing tokens

2024-11-28T01:28:45.573Z  2f3cd8e2-e043-4032-82d2-7442cc63335e  trce  [Information] Microsoft.AspNetCore.Authorization.DefaultAuthorizationService: Authorization failed. These requirements were not met:

DenyAnonymousAuthorizationRequirement: Requires an authenticated user.

```

Is this a regression?

Yes

Regression additional context

No response

Platforms

iOS

OS Version

18.1, 17.4

Device

iPhone 16, iPhone 12

Specific to simulators

No response

Additional context

  • I have reviewed the changes in version 2.39.0 (#3827), which include fixes related to authentication and session management.
  • The problem might be addressed by these updates, but I am seeking confirmation before upgrading.
  • Attached is a snippet of my AmplifyAuthManager class implementation for reference.
public actor AmplifyAuthManager: AuthManagerProtocol, TokenProvider {
    let auth: AuthCategory
    
    public static let manager = AmplifyAuthManager()
    
    private init() {
        do {
            try Amplify.add(plugin: AWSCognitoAuthPlugin())
            try Amplify.configure()
        } catch {
            print("Failed to initialize Amplify with \(error)")
        }
        
        auth = Amplify.Auth
#if DEBUG
        Amplify.Logging.logLevel = .verbose
#endif
    }
    
    public func signOut() async -> Result<AuthStatus, GenericAPIError> {
        do {
            guard try await auth.fetchAuthSession().isSignedIn else {
                return .success(.signedOut)
            }
            
            let signOutState = await auth.signOut()
            guard let signOutResult = signOutState as? AWSCognitoSignOutResult else {
                return .failure(.other("Sign out failed")) 
            }
            switch signOutResult {
            case .complete:
                return .success(.signedOut)
            case .partial(revokeTokenError: let revokeTokenError,
                          globalSignOutError: _,
                          hostedUIError: _):
                return .failure(.other(String(describing: revokeTokenError)))
            case .failed(let error):
                return .failure(.authError(error.toLoginError()))
            }
        } catch {
            debugPrint("AmplifyAuthManager signOut failed")
            debugPrint(error.localizedDescription)
            return .failure(.other(""))
        }
    }
    
    func fetchAuthSession() async -> Result<AuthStatus, GenericAPIError> {
        do {
            let authSession = try await auth.fetchAuthSession()
            let tokens = try getTokens(authSession as? AuthCognitoTokensProvider)
            if authSession.isSignedIn, let _ = tokens {
                return .success(.signedIn)
            } else {
                return await signOut() 
            }
        } catch let authError as AuthError {
            return .failure(.authError(authError.toLoginError()))
        } catch {
            return .failure(.someThingWentWrong(error))
        }
    }

    private func getTokens(_ tokenProvider: AuthCognitoTokensProvider?) throws -> AuthCognitoTokens? {
        try tokenProvider?.getCognitoTokens().get()
    }
}

Metadata

Metadata

Assignees

Labels

authIssues related to the Auth categoryquestionGeneral question

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions