I have a problem implementing an app on Flutter using flutter_bloc. I understood the core concepts but I found an "edge case" where there is not examples or guides (at least that I could find):
(I will simplify the problem) I have a bloc called AuthBloc that manages the App. If the state is NotAuthenticated then the App should show the LoginScreen but if is Authenticated the App should show the HomeScreen. Inside the HomeScreen I have 4 blocs, where each bloc has its states and events, but all of them has dependencies on different Repositories to get some data from an API.
All the Repositories need a token to make the API requests. The first problem came here. How can I get the token from all the repositories? If I use a UserRepository to store the token, I will need to pass it as dependency to each Repository (probably works but I don't think its the right way to do it). So, what can be the right way to manage this?
The second problem is:
If somehow I can get the token on all the repositories queries, what happens when the token is revoked? The app should return to the LoginScreen and for that I would need to notify the AuthBloc through an event (for example InvalidTokenEvent). And the AuthBloc should change its state to NotAuthenticated and that will rebuild the LoginScreen. But the question is: How can I notify the AuthBloc from other blocs or repositories? The first idea I had is through dependency injection: I can pass the AuthBloc to every other bloc in the constructor, so when the repository request returns a token expired, the XBloc can call AuthBloc.add(InvalidTokenEvent). But again, if I have a lot of blocs I would need to do that in each bloc. So, what's the right way to do this?
Thank you for any help!
To answer your first problem:
Your repositories should not be handling the API authentication. That should be the job of the data layer under the repository layer.
What I recommend is having one instance of a http client and then provide this instance to all the repositories. This way your client can have an interceptor that handles adding the saved token to all your requests. So your repositories could look something like this:
class OrderRepository {
const OrderRepository(this.httpClient);
final HttpClient httpClient;
}
Then the rest would be as simple as initializing your httpclient then pass it to your repositories which you can provide to your app and blocs by using RepositoryProvider or MultiRepositoryProvider. Then do the same thing with your repositories and blocs passing your repositories to your blocs inside of your blocproviders.
To answer your second problem:
If authenticating and passing your token to all requests can be handled at the http client layer so should unauthenticating and revoking the token. Therefore to reflect this in your authentication state your AuthRepository should listen to your http client and similarly your AuthBloc should listen to your AuthRepository. You can do this by exposing a stream of your authentication status in both your http client and your AuthRepository that gets listened to in your auth bloc.
So it would look like this:
http client gets a 401 error so it removes the token from storage and then adds the unauthenticated status to the stream. This stream is then exposed in auth repository and then in auth bloc have a stream subscription which listens to the authentication status to emit an unauthenticated state.
All the Repositories need a token to make the API requests. The first
problem came here. How can I get the token from all the repositories?
If I use a UserRepository to store the token, I will need to pass it
as dependency to each Repository (probably works but I don't think its
the right way to do it). So, what can be the right way to manage this?
This is not a bad practice to apply (adding it as dependency), but to make it easier, you can use getIt and injectable libraries to have a proper dependency injection solution.
Another way is, adding an interceptor to your networking layer, which is, before making a http request you can intercept your request, add token to your request in that layer and proceed to requesting phase.
Most of the networking libraries has request and response interceptors like below:
Dio
Chopper
But this is not an issue of Bloc library.
If somehow I can get the token on all the repositories queries, what
happens when the token is revoked?
You can add another response interceptor to detect if you have unauthenticated response so you can logout user.
Using getIt, you can gether that bloc from your global dependency container and logout user.
Related
I have a login block, if the login data is successful, I need the OTP verification request, I need the successful login data to request the verification block. how do i get the data in the verification block?? by implementing a clean architecture
Navigate with named routes and pass it as an argument, put it inside the widget constructor or wrap your MaterialApp with your Bloc to access the instance globally.
You could also work with singletons, service locators, etc. This may also help you https://pub.dev/packages/get_it
I'm using a Cubit-repository-datasource design separated by feature.
Title mostly says it all, but to extrapolate: I have an authentication Cubit. It is under the /authentication feature. I have another feature, /posts , that needs an access token from the /authentication feature to send an API request. This token is provided to it from the widget tree (authentication cubit is provided from the top of the widget tree). When a method from /posts's cubit is called: getPosts(int numOfPosts, String accessToken), it takes an access token from the provided widget tree's authentication cubit and passes it to the posts cubit. From here, it sends the request down to the repository layer, then to the data layer.
HOWEVER, what happens if the token is invalid? What happens if it has been tampered with? What happens if it's null? Then, I'd like the token to first be refreshed, and then to repeat the same call for posts using the refreshed access token. However, that "refresh the access token" method is inside the authentication cubit, not the posts cubit. How then should I call it? Can I call the refreshAccessToken() method (inside the /authentication feature's repository or data layer) from inside the repository or data layer of the /posts feature?
Is this sort of "crossing-feature" bad?
Thanks!
I second the comment made by #FabriBertani. The bloc/cubit shouldn't know anything about how to get the posts. It should just do getPosts(int numberOfPosts).
That method should e.g. come from an interface (abstract class in Dart) which in turn is implemented in a different layer (e.g. data/repository/service layer).
That implementation can then in turn handle what is needed to fetch the data from your API. It could e.g. have an authentication service injected to it from where it gets the token.
I need a mechanism to store and access request specific data in Akka HTTP. Is it possible without sending values around to each actor that is called from the route?
Let's say I want to log performance of all operations, including request id, so I'm able to search logs by request id. So when logging inside actor, it would be great to do something like Request.id.
Note that API does not implement session, since this is a specific service which runs behind main API (which is doing authentication etc).
Is there any library or built in way suitable for this?
Thanks in advance
I have a Flutter app which holds a username and a token to communicate with a web service.
How can I manage the username and token efficiently using best practices? Currently I am writing them into a DB and select them each time I want to do a request.
I tried to use bloc provider flutter bloc with a BlocProvider. I have the states LoggedIn and LoggedOut and the events Login and Logout.
Furthermore, I had a look at
secure storage, but I can't get the data available throughout all pages.
Also, I am not using the firebase API.
Let me know if I should provide some code snippets.
I use SharedPreferences now. The API is very simple and I wrote a wrapper to get rid of the (Strings) keys. Furthermore, the wrapper holds the values for the current session. The advantage of that is, that I can address the values directly instead of needing to read them asynchronously.
I'm building a React.js application that will interact with my REST API built in Go.
React will use Javascript Fetch API to send requests to my API.
The problem is I would like to secure my API from being requested from elsewhere. No one should directly be able to access my API either through the URL or through any other client like Postman.
I know what JWT is but this does not solve my problem because anyone can access the token through the browser and then continue to request the API outside the React client using the token.
I have researched extensively but nothing has really fit my description.
Thanks a lot for you help, in advance.
This is an inherently unsolvable problem. React runs on the client. The client controls the code that it executes. Hence, any mechanism you use to restrict the API usage to just your React client will be discoverable and reusable in other client contexts. You cannot control the client, and attempts to do so will be broken if the payoff is valuable enough.
You can attempt to harden it somewhat by using short-term authorization tokens, but there is nothing preventing that token from being grabbed and reused in another context.
If you have to restrict access to an API, you should have a public API which is less dangerous or privileged, and the public API should make use of your private API, effectively proxying the calls to hide the private API, as well as to ensure that only validated queries are executed against the more privileged API.
If you could describe the problem you're trying to mitigate, though, there may be other solutions available.