Shopify Storefront API error Delegate Access Token - shopify

I've made progress (I think) with getting delegate access scope working on my custom app for my store. However, I keep getting this error:
Error: GraphQL Error (Code: 422):
{"response":{"errors":{"delegate_access_scope":["The access scope
can't be empty."]},
To simply get this working I'm using the example from the docs:
const accessToken = gql`mutation {
delegateAccessTokenCreate(input: { delegateAccessScope: ["write_orders" ], expiresIn: 3600 }){
delegateAccessToken {
accessToken
}
shop {
id
}
userErrors {
field
message
}
}
}`
I'm kind of at my wits end here as I finally realized that the delegate.json actually needs the ADMIN key rather than the storefront even though I want to use this with the storefront API (which is weird). All I want to be able to do is create a new customer with a password via this API.
Thanks in advance.

Maybe you just need to change delegateAccessScope: to delegate_access_scope per doc, https://shopify.dev/apps/auth/oauth/delegate-access-tokens/create
{
"delegate_access_scope": [
"write_orders"
],
"expires_in": 3600
}

Ok, so I figured it out. I don't actually want a delegateAccessToken to create a user but to have a Storefront API Access Token. This may get a bit confusing but you use your Admin Access Token to request a storefront access token like so (I use graphql-request on npm):
const accessToken = gql`mutation storefrontAccessTokenCreate($input: StorefrontAccessTokenInput!) {
storefrontAccessTokenCreate(input: $input) {
shop {
id
}
storefrontAccessToken {
accessToken
}
userErrors {
field
message
}
}
}`
const accessTokenVars = {
"input": {
"title": "my-access-token"
}
}
const queryAccessTokenData = await adminGraphQLClient.request(accessToken, accessTokenVars);
From here you now have a Storefront Access Token and can make a call via Oauth to create a customer like so:
const shopifyUserQuery = gql`mutation customerCreate($input: CustomerCreateInput!) {
customerCreate(input: $input) {
customer {
id
firstName
lastName
acceptsMarketing
}
customerUserErrors {
field
message
code
}
}
}`
const shopifyUserVars =
{
"input": {
"firstName": values.firstName,
"lastName": values.lastName,
"email": values.email,
"password": values.password,
"acceptsMarketing": false,
}
}
// We need to switch the default storefront headers over to our private API key
sfGraphQLClient.headers = {
'X-Shopify-Storefront-Access-Token': queryAccessTokenData.storefrontAccessTokenCreate.storefrontAccessToken.accessToken,
'Content-Type': 'application/json'
}
const shopifyCreateCustData = await sfGraphQLClient.request(shopifyUserQuery, shopifyUserVars);
This will now create the user using the Storefront API.

Related

How to get user email using Google Sign In expo Auth Session?

At moment im using this snippet of code to sign in to google, but i cant get user email… anyone know how to do this?
var LoginGoogle = () => {
const [request, response, promptAsync] = Google.useAuthRequest({
androidClientId: 'xxxxxxx.apps.googleusercontent.com',
expoClientId: 'xxxxxxx.apps.googleusercontent.com'
},{
scopes: ["email"]
},{});
React.useEffect(() => {
if (response?.type === 'success') {
const { authentication } = response;
console.log(response);
}
}, [response]);
return (
<GoogleSocialButton disabled={!request} onPress={() => {promptAsync()}} />
)
}
response returns object with links instead of email
I wish this is written in the expo docs. I would like to add a few points from the first answer:
First if you need code snippets on how to fetch user data after getting the access token, you can refer to this github issue: https://github.com/expo/expo/issues/8384
access token can be received by the following code after receiving the response object:
const { authentication: { accessToken } } = response;
then, you can create a function like this:
async function fetchUserInfo(token) {
const response = await fetch('https://www.googleapis.com/oauth2/v3/userinfo', {
method: 'GET',
headers: {
Accept: 'application/json',
Authorization: `Bearer ${token}`,
'Content-Type': 'application/json'
},
});
return await response.json();
}
and get the user object (which contains the user email, profile, photo, etc) by something like this inside an async function:
const user = await fetchUserInfo(accessToken);
But NOTE for the user object, using https://www.googleapis.com/oauth2/v2/userinfo and https://www.googleapis.com/oauth2/v3/userinfo, will yield slightly different result/object ; in particular for v3, since Google implements the OpenID Connect API, there is no "id" attribute anymore, "id" will be called "sub".
sources:
How to identify a Google OAuth2 user?
https://developers.google.com/assistant/identity/google-sign-in-oauth
https://github.com/expo/expo/issues/8384
Example of a user object in v3:
Object {
"email": "xxxxx#gmail.com",
"email_verified": true,
"family_name": "John Deer",
"given_name": "John",
"hd": "gmail.com",
"locale": "en",
"name": "John Deer",
"picture": "https://lh3.googleusercontent.com/a/asdfjasdklfjaslkf",
"sub": "10998837733652322",
}
Hope this helps someone in the future...!
EDIT: if you need the id_token checkout this one:
expo-auth-session/providers/google Google.useAuthRequest
I am using AuthSession as well in my RN app and I stumbled with this problem. After going through Google API Docs, found out you can pass the access token from the useAuthRequest response to https://www.googleapis.com/oauth2/v3/userinfo?access_token= ACCESS_TOKEN.

Strapi / Nuxt - Can't find custom route

I've used this to setup auth in strapi and nuxt:
Auth with Strapi and Nuxt
I'm currently trying to retrieve the items specific to a authenticated user (already checked out this strapi - restrict user to fetch only data related to him). To do this I created a custom route in Strapi (/api/routine/config/routes.json):
{
"method": "GET",
"path": "/routines/me",
"handler": "Routine.me",
"config": {
"policies": []
}
}
and a custom controller (/api/controllers/Routine.js):
module.exports = {
me: async (ctx) => {
const user = ctx.state.user;
if (!user) {
return ctx.badRequest(null, [{ messages: [{ id: 'No authorization header was found' }] }]);
}
const data = await strapi.services.routine.find({user:user.id});
if(!data){
return ctx.notFound();
}
ctx.send(data);
},
};
I already gave permission through Strapi admin for authenticated users to access 'me'. When I hit the endpoint from Nuxt:
const routines = await axios.get(http://localhost:1337/routines/me)
I get this error:
GET http://localhost:1337/routines/me 404 (Not Found)
Why is the custom route not found? Am I using the wrong endpoint?
Maybe you have already solved it, but it seems like you forget to send the authentication header with the request.
const routines = await axios.get(
'http://localhost:1337/routines/me', {
headers: {
Authorization:
this.$auth.getToken('local'),
},
}
It was a fault in my Strapi routes config. Answer was provided through the amazingly helpful Strapi forums:
403 forbidden when calling custom controller from Nuxt
Here is the problem:
{
"method": "GET",
"path": "/routines/:id",
"handler": "routine.findOne",
"config": {
"policies": []
}
},
{
"method": "GET",
"path": "/routines/me",
"handler": "routine.me",
"config": {
"policies": []
}
So basically you are hitting the first route right now and it assumes that
me is actually an :id. Koa is making the verifications with regex so in this case it takes the first matched route. Move the route with /me above that one with /:id

Lose user data in Nuxt-auth fetchUser CustomStrategy

Hi everyone!
I have my own custom strategy to get token, and all is good, but when a refresh page I lose user data and fetchUser does not works. It doesn´t send the params to API to get again the user data.
the workflow is next:
1- send params to token api and get token
2- send params to login API to get the user
//nuxt.config.js
customStrategy: {
_scheme: '~/schemes/customScheme',
endpoints: {
login: {
url: '/api/v1/token',
method: 'post',
propertyName: 'token',
headers: {'x-channel-id': 1}
},
user: {
url: '/api/v1/login',
method: 'post',
propertyName: false,
headers: {'x-channel-id': 1}
},
logout: null
}
}
customScheme.js
import LocalScheme from '#nuxtjs/auth/lib/schemes/local'
export default class CustomScheme extends LocalScheme {
_setToken (token) {
if (this.options.globalToken) {
// Set Authorization token for all axios requests
this.$auth.ctx.app.$axios.setHeader(this.options.tokenName, token)
}
}
_clearToken () {
if (this.options.globalToken) {
// Clear Authorization token for all axios requests
this.$auth.ctx.app.$axios.setHeader(this.options.tokenName, false)
}
}
mounted () {
if (this.options.tokenRequired) {
const token = this.$auth.syncToken(this.name)
this._setToken(token)
}
return this.$auth.fetchUserOnce()
}
async login (endpoint) {
if (!this.options.endpoints.login) {
return
}
// Get token
const result = await this.$auth.request({
...endpoint
},
this.options.endpoints.login
)
// Set token
if (this.options.tokenRequired) {
const token = this.options.tokenType
? this.options.tokenType + ' ' + result
: result
this.$auth.setToken(this.name, token)
this._setToken(token)
}
// If result I get and set user
if (result) {
const user = await this.$auth.request({
...endpoint
},
this.options.endpoints.user
)
this.$auth.setUser(user);
}
}
async fetchUser (endpoint) {
// User endpoint is disabled.
if (!this.options.endpoints.user) {
this.$auth.setUser({})
return
}
// Token is required but not available
if (this.options.tokenRequired && !this.$auth.getToken(this.name)) {
return
}
// Try to fetch user and then set
try{
const user = await this.$auth.requestWith(
this.name,
endpoint,
this.options.endpoints.login
)
this.$auth.setUser(user)
} catch (error){
console.log(error)
}
}
}
When I set this.$auth.setUser(user) in login() method all is fine and app redirect me to /dashboard page and the user information (like role and email) is displayed on navBar but when I refresh page I lose user data. The app try to fetchUser but it give me a 400 error because user and password not sent.
Another thing I don´t understand is Why endpoint parameter is undefined in async fetchUser (endpoint) ??? . I think there is an issue in this part.
I hope u can help me
Regards
I just remove all this library and did my own custom Nuxt authentication
https://nemanjadragun92.medium.com/nuxt-js-custom-authentication-245d2816c2f3

405 error with JIRA REST API using node js

I am trying to create an automated JIRA ticket using the REST API but I keep getting a 405 error.
I am using the examples here: https://developer.atlassian.com/server/jira/platform/jira-rest-api-examples/
Also, when I visit the post URL directly I do not get any errors so I doubt it is a server issue. Any ideas?
var Client = require('node-rest-client').Client;
client = new Client();
// Provide user credentials, which will be used to log in to Jira.
var loginArgs = {
data: {
"username": "user",
"password": "pass"
},
headers: {
"Content-Type": "application/json"
}
};
client.post("https://jira.mydomain.com/rest/auth/1/session", loginArgs, function(data, response) {
if (response.statusCode == 200) {
//console.log('succesfully logged in, session:', data.session);
var session = data.session;
// Get the session information and store it in a cookie in the header
var args = {
headers: {
// Set the cookie from the session information
cookie: session.name + '=' + session.value,
"Content-Type": "application/json"
},
data: {
// I copied this from the tutorial
"fields": {
"project": {
"key": "REQ"
},
"summary": "REST ye merry gentlemen.",
"description": "Creating of an issue using project keys and issue type names using the REST API",
"issuetype": {
"name": "Request"
}
}
}
};
// Make the request return the search results, passing the header information including the cookie.
client.post("https://jira.mydomain.com/rest/api/2/issue/createmeta", args, function(searchResult, response) {
console.log('status code:', response.statusCode);
console.log('search result:', searchResult);
});
} else {
throw "Login failed :(";
}
});
I am expecting the Jira ticket of type REQ to be created with the details I added in the fields section.
I believe you are using the incorrect REST API; what you're currently doing is doing a POST to Get create issue meta which requires a GET method, hence, you're getting a 405. If you want to create an issue, kindly use Create issue (POST /rest/api/2/issue) instead.

Unable to use Auth0 to get delegation token

In my Angular2 app, I want to use Auth0 to get a delegation token so I could use it to custom sign into firebase. I followed the sample here to setup my Auth0 service and got it working.
The problem I'm having now is getting my delegation token and sign into Firebase with it. The example here shows how it's done, but I'm getting an EXCEPTION: Cannot read property 'auth0' of undefined when I try to declare my auth0 instance and use it to get my delegation token. What did I do wrong?
In my index.html I included the following scripts:
<script src="http://cdn.auth0.com/js/lock/10.7/lock.min.js"></script>
<script src="https://cdn.auth0.com/w2/auth0-7.4.min.js"></script>
I also tried in my terminal to install auth0:
npm install auth0
npm install auth0-js
My auth service currently looks like this:
// app/auth.service.ts
import { Injectable } from '#angular/core';
import { tokenNotExpired } from 'angular2-jwt';
import { AngularFire } from 'angularfire2';
// Avoid name not found warnings
declare var Auth0Lock: any;
declare var Auth0: any;
#Injectable()
export class Auth {
// Configure Auth0
lock = new Auth0Lock('AUTH0_CLIENT_ID', 'AUTH0_DOMAIN', {});
constructor(private af: AngularFire) {
// Add callback for lock `authenticated` event
this.lock.on("authenticated", (authResult) => {
this.lock.getProfile(authResult.idToken, function(error:any, profile:any){
if(error){
throw new Error(error);
}
localStorage.setItem('id_token', authResult.idToken);
localStorage.setItem('profile', JSON.stringify(profile));
//options to be used with auth0 instance to get delegation token
var options = {
id_token : authResult.idToken,
api : 'firebase',
scope : 'openid name email displayName',
target: 'AUTH0_CLIENT_ID'
};
//----->ERROR HERE, can't read auth0 property
this.auth0.getDelegationToken(options, function(err, result){
console.log(result);
if(!err){
this.af.auth().signInWithCustomToken(result.id_token).catch(function(error) {
console.log(error);
});
}
});
});
});
}
public login() {
// Call the show method to display the widget.
this.lock.show();
}
public authenticated() {
// Check if there's an unexpired JWT
// This searches for an item in localStorage with key == 'id_token'
return tokenNotExpired();
}
public logout() {
// Remove token from localStorage
localStorage.removeItem('id_token');
}
}
You also need to create auth0 instance as shown here
var auth0 = new Auth0({ domain : AUTH0_DOMAIN, clientID: AUTH0_CLIENT_ID });
I found a workaround for this issue. I was stuck on this exact same problem and I think it has got to do with typscript importing of the auth0 module. Instead of using the auth0 module I simply made an HTTP POST request to my Auth0 account's delegation endpoint:
let headers = new Headers({ 'Content-Type': 'application/json' });
let options = new RequestOptions({ headers: headers });
this.http.post('https://<Your domain>/delegation',
{
"client_id": "<Your client ID>",
"grant_type": "urn:ietf:params:oauth:grant-type:jwt-bearer",
"id_token": <Your auth0 Id Token>,
"target": "Your client ID",
"scope": "openid",
"api_type": "<Your delegation choice (mine was "aws")>",
}, options)
.map((res:Response) => res.json())
.subscribe(
data => localStorage.setItem('awsToken', JSON.stringify(data.Credentials)),
err => console.log(err),
() => console.log('Authentication Complete')
);
This will store the acquired credentials in your browser's local storage. Note: there may be some additional parameters required by Firebase that I am unaware of as I am using AWS. Also you will need the following imports for this HTTP request:
import { Http, Response, Headers,RequestOptions } from "#angular/http";
import { Observable } from 'rxjs';
import 'rxjs/add/operator/map';