right now I'm trying to create a proof of concept on spartacus. The concept is to manually check out a cart for an anonymous customer.
I came to a point, where I was wondering whether it is possible to authenticate a client or user manually with spartacus.
So my question in general: What is the best practice to manually authenticate the client/user in spartacus? Some code examples would be great :)
Best regards and thanks in advance
Not sure exactly what you mean by "manually" authenticate.
In spartacus if you want to authenticate the client (the app) it's quite simple. The client-token.interceptor is setup to catch request containing a specific header and add the client token to the request. If Spartacus doesn't have the token in memory it will request it.
To do so you should use add the USE_CLIENT_TOKEN to your request header. Here is an example:
const url: string = '/url';
let headers = new HttpHeaders({
'Content-Type': 'application/json',
});
// The line bellow add the token to the header
headers = InterceptorUtil.createHeader(USE_CLIENT_TOKEN, true, headers);
return this.http
.post<User>(url, { data: data }, { headers });
As for the user authentication, the user token will be added to all request as long as the user is authenticated in Spartacus. There is no "automatic" mechanism to fetch it. The token is fetched via login.
Hope this helps!
There are a few things you have to do in case of a guest checkout.
First thing is to enable guest checkout in the config with:
checkout: { guest: true }
Then the first step of the checkout should be /checkout-login page.
There user needs to provide email address that is assigned to a specific cart.
We recognize guest checkout by that assigned email to the cart. Otherwise, checkout components will behave like it is normal checkout. Because of that, there are calls for user addresses or payments.
In case you want everything on one page (setting email address, delivery, payments etc.) you have to override default implementation for checkout components to avoid all these calls for the logged user.
And calls for setting address and payment in case of guest checkout doesn't have to by authorized (you can see that on demo guest checkout these calls have undefined in Authorization header).
And for client authorization, it is nicely described in https://stackoverflow.com/a/60821200/4666829
Related
I have a React Native app that uses Strapi for its main API.
Some of the API endpoints require authentication so I've used the Auth0 provider and that's all working fine.
A user is now able to log in and I'm securely storing their access_tokens.
So far, Auth0 only gives me an access_token, a refresh_token, an id_token (jwt containing name and email etc) and expiry times for the tokens.
But I'm wondering if it's possible to be able to store a users preferences like whether they prefer dark or light theme etc and extra info such as a user_id in Strapi and let them update it after logging in with Auth0.
The catch is that only that user should have read/write access to their own data.
I can't see any docs or guidance on this kind of thing. Has anyone else managed to implement this kind of thing and if so, a rough approach would be great!
Thanks!
Well, one way of the doing this is creating a OAuthUsers collection in strapi, which will hold basic details of a user like:
first_name
last_name
email
When a user registers on Auth0 and returns back to your site, you can take the basic details that were returned from the identity management platform and store it in strapi under the OAuthUsers collection.
Now, coming to your question on how to store the preferences of the user, what you can do is create another collection called preferences with following attributes:
is_dark_theme
OAuthUser (Make this a one-to-one relation with OAuthUsers collection )
Every time a logged in user updates his preferences it will first come and create an entry in this collection if not already existing. How you can check if an entry exists for a user is by using the email from the JWT token itself, that you attach as the bearer token on the API calls. I will assume, you already know how to decode a JWT token.
So a rudimentary design would be like so:
const is_dark_theme = request.body.is_dark_theme; // 1 or 0 for light theme
const user = await strapi.services.OAuthUsers.find({ email: '[email from JWT]'});
const preference = await strapi.services.preferences.find({ OAuthUser: user.id });
if(preference)
await strapi.services.preferences.update({is_dark_theme}, {id: preference.id});
else
await strapi.services.preferences.create({is_dark_theme, user: user.id});
So per this, what will happen is the user will only be able to update his own details and never be able to touch the preferences of other users as the user will only be able to pass the is_dark_theme parameter from front end and rest of the information will be taken from the JWT token.
Zapier has been a handy way to connect to API's like quickbooks. However there is very little documentation on how to set this up, which caused me to spend weeks figuring it out (hopefully for you this will help!). This is a Q&A post, however if anyone has input that will improve this information please feel free to share here.
If you find yourself in a situation like mine and you are looking on how to also make an 'action' or 'trigger' for quickbooks just leave a comment and I can work on a tutorial for those as well.
If I have posted this in the wrong format for Stack Overflow please let me know and I will correct that or move it to a blog.
Depending on how things go I may end up submitting my zap for public use (My zap finds estimates by their ID and returns everything, useful for when you have a web-hook on Quickbooks). Anyway, all the information presented in this post is for the OAuth2 setup.
Here is the documentation I used:
API OAuth 2.0
Playground
Question: How do I connect Quickbooks API to a custom app in Zapier Developer with OAuth2?
To start this answer assumes you have a Quickbooks and Zapier dev account. It also assumes you have begun to setup your first Zap and are now working on authentication.
In Zapier Dev, choose Authentication tab and select OAuth2
Leave "Configure your Fields" blank and press continue
In "Enter your Application Credentials" enter your credintials from your Intuit keys page
Now in "Add OAuth v2 Endpoint Configuration" enter the following as shown for the Authorization URL section:
Next define your scope, I used com.intuit.quickbooks.accounting openid email profile
We also have to get the "Access Token Request", set it up like this:
Finally add the refresh request:
Set "Automatically Refresh Token" to checked.
Now, the next part is custom, but I set up my test request to a random query (you can do the same if you want)
const options = {
url: 'https://sandbox-quickbooks.api.intuit.com/v3/company/ENTERYOURREALMID/query?query=select*from Invoice&minorversion=38',
method: 'GET',
headers: {
'Authorization': `Bearer ${bundle.authData.access_token}`,
'content-type': 'application/x-www-form-urlencoded',
'accept': 'application/json'
},
params: {
},
body: {
}
}
return z.request(options)
.then((response) => {
response.throwForStatus();
const results = z.JSON.parse(response.content);
// You can do any parsing you need for results here before returning them
return results;
});
Just toss in your RealmID in the http link (you can get the REALMID by clicking myaccount in Quickbooks, this is the same as Company ID).
Once you connect and run it should enter the HTTP Headers for you. If not, then for all sections they are same:
content-type: application/x-www-form-urlencoded
accept: application/json
That's it! Connect your account and you should be good to go!
NOTES:
-Quickbooks will require a refresh each 100 days.
-Remember that you must use backticks ` over single quotes ' if you are using a
Zapier variable.
I have successfully set up Graph.cool Auth0 authentication and created a User through Relay as described here.
Next I'd like to actually query graph.cool on behalf of this user. As a first step, I simply manually modified the Relay setup to specify the same auth token as was used to create the User in the first place (through the idToken on type AUTH_PROVIDER_AUTH0):
Relay.injectNetworkLayer(
new Relay.DefaultNetworkLayer(process.env.GRAPHQL_ENDPOINT, {
headers: {
Authorization: 'Bearer XXX.YYY.ZZZ',
},
})
);
However, the app stops rendering and I just get a console warning RelayPendingQueryTracker.js:153 Server response was missing for query Index. Any hints?
When calling the signinUser or createUser mutation, a Graphcool token is returned in the payload. https://www.graph.cool/docs/faq/graphcool-session-user-goij0cooqu
This is the token you need to use in the Authorization header instead of the Auth0 idToken.
Maybe it can also be a help to take a look at how we do it in the dashboard https://github.com/graphcool/dashboard/blob/master/src/views/LoginView/LoginView.tsx
Hope this helps!
If I have: users, and I need to log in with api rest. What's the best way to do it?
1 /users/id/password
2 /users?id=id&password=pass
If I use the second option, I will need to validate if there are get parameters. If not, It will return all results.
This is not the answer I want now:
REST API Login Pattern
The link you added is valid, REST APIs are stateless, so they can't login in the traditional way, you MUST store the client session on the client side. If you use HTTPs you won't need login. If you don't, then your API won't be secure, so using password won't have any protection. I think that's all.
If you want to both stay stateless and send tokens, then you have to sign for example the user id on the server. So by the next request you can send both the user id and the signature instead of the email and password. This way the server will know that you have been logged in earlier to the account the user id belongs to. I don't recommend you to use the URI for sending sensitive data. It is better to use the request body with POST. The URI structure depends on your taste, I would use something like this:
POST /users/1/tokens/ {email: "..", password: ".."}
201 {id: 1, expires: "..", signature: ".."}
Be aware that you have to send every variables you signed, so, the id, the expiration time (added by the server), probably the ip address, a random number, etc... You MUST not store anything on the server (including the token), otherwise the communication will be stateful.
I am not a security expert, but I think this solution does not make sense in most of the cases, so you need to justify somehow, why your API needs it. It is used for example for signing each request coming from 3rd party clients. If you cannot justify it, I recommend you to use the default approach, which is using HTTPS, logging in on the client side and sending HTTP Authorization header with email and password by every request.
I would use a POST method with the login / password provided within the payload:
POST /login
Content-Type: application/json
{ username: 'some username', password: 'some password' }
In addition, the following link could give you some hints about authentication within RESTful services:
Implementing authentication with tokens for RESTful applications - https://templth.wordpress.com/2015/01/05/implementing-authentication-with-tokens-for-restful-applications/
Hope it helps you,
Thierry
I have a problem authenticating users for my new Symfony2 application.
This applications gets all the info through an API, so no database is used. When a user goes to login page, he introduce the user and password in the login form. Then, I have to authenticate him using an API call. This API call returns "false" if it's not a user, and return a token key and a token secret if its a correct user. With this token key and secret, during the user session, I can make all the API requests I need for rendering all the pages of the application. Once the user session is over and token key and secret are erased, the user has to login again.
I don't know really how ti implement that. I read this http://symfony.com/doc/current/cookbook/security/custom_provider.html and that http://symfony.com/doc/current/cookbook/security/custom_authentication_provider.html, and I'm still so lost... :(
Can any one help me?
Thank you so much :)
If you want to write custom authentication you have found the correct links. As an example you can see the implementation of the OAuth authorization HWIOAuthBundle. But keep in mind that this type of authentication creates a user on your system. If you do not use a database, you must make a request to the API every time user send a request.
First you need to understand that there is no magic. On every request symfony checks if url matches one of the specified firewalls (see secutity.yml). Listener that fired you can see in the firewall factory. If matches are found, the action switches to the corresponding AuthenticationListener. Listener attempts to authenticate the credewntials by creating Token, which is sended to AuthenticationProvider
$this->authenticationManager->authenticate(new UsernamePasswordToken($username, $password, $this->providerKey));
in AuthenticationProvider
public function authenticate(TokenInterface $token) {
...
}
AuthenticationProvider try to get user via UserProvider. In case of success, Token stored in the session. On subsequent requests, ContextListener comes into play first, checks the session, extract token and send it to AuthenticationProvider similar.
In general terms, the scheme looks like that. More info you can find examining the source code of Symfony Security component.
Really good starting point is a UsernamePasswordFormAuthenticationListener. It just take login and password from request and make simplest UsernamePasswordToken.
protected function attemptAuthentication(Request $request)
{
...
}
Good luck!