Search code examples
swiftgetstream-io

GetStream add activity fails due 403


Trying out GetStream for Swift, I am not able to add an activity.

class MyActivity : Activity {}

...

let client = Client(apiKey: <MyApiKey>, appId: <MyApiKey>, token: <Token>)
let ericFeed = client.flatFeed(feedSlug: "user", userId: "eric")
let activity = MyActivity(actor: "eric", verb: "waves", object: "picture:10", foreignId: "picture:10")
ericFeed.add(activity) { result in
        print("!result!")
        print(result)
    }

The token is generated server-side, is in form eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoiZXJpYyJ9.AAAAAAAAAAAAAAAAA-AAAAAAAAAAAAAAAA-AAAAAAAA and:

  1. client.currentUserId returns eric (So, the token is correct?)
  2. The Callback of ericFeed.add(activity) is not called
  3. On my app's dashboard log, I see the attempt of adding the activity as failed, with error 403

I tried different ids (with different tokens), both actor: "eric" and actor: "user:eric". What could have gone wrong?

The code to generate the token (php server) is:

$userId = "eric";
$client = new GetStream\Stream\Client(<MyApiKey>, <MyAppSecret>);
$userToken = $client->createUserSessionToken($userId);

And I receive to logs on my dashboard:

log1


log2


Solution

  • There is a couple things that needs to keep in mind. First of all, probably your client was deallocated when the request was ended and that's why the callback wasn't called, but logs could show you that the request was done. I suggest you to use a shared Client instance and it would be easy to use. To setup a shared Client you need to write this:

    Client.config = .init(apiKey: "<MyApiKey>", appId: "<MyApiKey>", token: "<Token>")
    

    More about the Client setup in wiki page.

    The second important thing, that you have to create/update your Stream user. From the server side you are getting your Token with the Stream userId and can request the Stream user. The easiest way is to call Client.shared.create(user:) where user would be created/updated. So, it's still a part of the Stream Client setup:

    Client.shared.create(user: GetStream.User(id: Client.shared.currentUserId!)) { result in
        // Update the client with the current user.
        Client.shared.currentUser = try? result.get()
        // Do all your requests from here. Reload feeds and etc.
    }
    

    More info in docs.

    I suggest you to create feeds with only feedSlug parameter and the Stream userId would be taken from the Token. But it would be Optional, because the currentUserId is optional. For example:

    let ericFeed = Client.shared.flatFeed(feedSlug: "user")
    ericFeed?.add(activity)
    

    And for your activities, Stream clients should always use the current Stream user as an actor. So, we need to update the definition of your MyActivity.

    Finally, here is your code that should works:

    // Define your activity.
    class MyActivity: EnrichedActivity<GetStream.User, String, DefaultReaction> {
    // ...
    }
    
    // Setup Stream Client.
    Client.config = .init(apiKey: <MyApiKey>, appId: <MyApiKey>, token: <Token>)
    
    // Setup the current user.
    Client.shared.getCurrentUser {
        let ericFeed = Client.shared.flatFeed(feedSlug: "user")
        let activity = MyActivity(actor: Client.shared.currentUser!, verb: "waves", object: "picture:10", foreignId: "picture:10")
        ericFeed?.add(activity) { result in
            print("!result!")
            print(result)
        }
    }