Meteor loginWithApple oauth - "Service not configured" - javascript

I'm adding Apple login, the latest oauth package to join Meteor, but I'm running into the error message "Service not configured". It seems that a lot of the solutions [another] talk about using ServiceConfiguration to fix these errors, but I haven't had to initialize any of the other meteor logins such as loginWithGoogle or loginWithFacebook. Based on my reading through the github package Meteor.loginWithApple is configured the same way as these existing login functions. What configuration issue might be triggering this?
When I look at Meteor.settings.private.oAuth, apple is right there alongside google and facebook.
First, I installed these two https://atmospherejs.com/quave/accounts-apple, https://atmospherejs.com/quave/apple-oauth
meteor add quave:accounts-apple
meteor add quave:apple-oauth
Then set up the config in settings.json alongside facebook and google oauth per this guide.
settings.json:
"apple": {
"teamId": "yyexamplexx",
"clientId": "com.example.client",
"keyId": "zzexamplewq",
"secret": "zxcvsdfasdfexamplezlongstrxcvsdfasdf",
"redirectUri": "https://example.com/apple-redirect"
},
Client:
continueWithApple = () => {
Meteor.loginWithApple({}, function(err, res) {
if (err) {
console.log(err);
}
//running ok
});
};
<Form.Button
id="appleid-signin"
fluid
basic
className="continue apple"
data-color="black"
data-border="true"
data-type="sign in"
onClick={() => {
this.continueWithApple();
}}
>

For some reason the config oauth settings aren't being passed on, so we had to do something like the following in order to set up the credentials and stop the "Service not configured" error message:
Meteor.startup(() => {
// remove any existing service so you can configure the latest one
Accounts.loginServiceConfiguration.remove({ service: "apple" });
// setup apple login, drawing from your settings.json
Accounts.loginServiceConfiguration.insert(Meteor.settings.private.oAuth.apple);
...
)}
Our configuration looked something like:
"private": {
"oAuth": {
"apple": {
"secret": "-----BEGIN PRIVATE KEY-----\nxyzexamplexyz\n-----END PRIVATE KEY-----",
"redirectUri": "https://www.example.com/_oauth/apple",
"clientId": "com.example.client",
"teamId": "WXYZ8EXAMPLE",
"keyId": "456EXAMPLE",
"scope": "name%20email",
"responseMode": "form_post",
"responseType": "code",
"service": "apple"
}
It seems to be important that the redirectUri ends with _oauth/apple since meteor's loginWithApple is looking for that. Didn't need to handle the callback at all, the packages below take care of it.
meteor add quave:accounts-apple
meteor add quave:apple-oauth
Also important to put the %20 in the scope name%20email...it just worked.

Related

How do I find out what is actually set to "${ ... }" in AWS IAM policy?

I'm trying to limit access to items in Dynamo DB tables based on Cognito User Pool using Lambda IAM role policy.
In the process, I'm struggling to find what is actually set to "${cognito-identity.amazonaws.com:aud}" in the Lambda IAM policy below.
{
"Effect": "Allow",
"Action": [
"dynamodb:Scan",
"dynamodb:Query",
"dynamodb:GetItem",
"dynamodb:PutItem",
"dynamodb:UpdateItem",
"dynamodb:DeleteItem",
"dynamodb:DescribeTable"
],
"Condition": {
"ForAllValues:StringEquals": {
"dynamodb:LeadingKeys": "${cognito-identity.amazonaws.com:aud}"
}
},
"Resource": "arn:aws:dynamodb:ap-southeast-2:*:*"
}
I'm assuming it is either Application Client ID or Identity Pool ID like "ap-southeast-2:xxxxxxxx-aaaa-bbbb-cccc-123456789012", but is there a way to output what is actually set to "${cognito-identity.amazonaws.com:aud}" on runtime to confirm?
I am relatively new to AWS.
Updated - Additional Information
Just before calling the Lambda via API Gateway, I can see something like "xxxxxxxxnv0ff03e9joqh3om3h" (my App Client ID) using below:
const session = await Auth.currentSession();
alert(session.idToken.payload.aud); //something like "xxxxxxxxnv0ff03e9joqh3om3h"
However, I get AccessDeniedException in Lambda DynamoDB query with the App Client ID.
ExpressionAttributeValues: {
":partitionkey": "xxxxxxxxnv0ff03e9joqh3om3h",
},
I can avoid AccessDeniedException error by changing the IAM Policy to:
"Condition": {
"ForAllValues:StringEquals": {
"dynamodb:LeadingKeys": "123abc"
}
},
and my Lambda DynamoDB query to:
ExpressionAttributeValues: {
":partitionkey": "123abc",
},
I've tried Cognito Identity Pool ID too, but no luck.
The mapped values for aud and sub are provider specific and outlined in the documentation.
In the case of Cognito Userpool federation it will be set to the client ID.

My Dialogflow chatbot refuses to deploy JavaScript fulfillment code

Dialogflow, and Google Cloud Console, refuses to publish my fulfillment code that I made on the Inline Editor.
Here is a code snippet from my index.js file:
'use strict';
const functions = require('firebase-functions');
const {google} = require('googleapis');
const {WebhookClient} = require('dialogflow-fulfillment');
const {Card, Suggestion} = require('dialogflow-fulfillment');
process.env.DEBUG = 'dialogflow:debug'; // enables lib debugging statements
exports.dialogflowFirebaseFulfillment = functions.https.onRequest((request, response) => {
const agent = new WebhookClient({ request, response });
console.log('Dialogflow Request headers: ' + JSON.stringify(request.headers));
console.log('Dialogflow Request body: ' + JSON.stringify(request.body));
function Weather(agent) {
const state = agent.parameters['geo-state-us'];
const city = agent.parameters['geo-city-us'];
agent.add(`The weather in ${city}, ${state} is fine and mild.`);
}
let intentMap = new Map();
intentMap.set('AskCity', Weather);
agent.handleRequest(intentMap);
});
function welcome(agent) {
agent.add(`Welcome to my agent!`);
}
function fallback(agent) {
agent.add(`I didn't understand`);
agent.add(`I'm sorry, can you try again?`);
}
// // Uncomment and edit to make your own intent handler
// // uncomment `intentMap.set('your intent name here', yourFunctionHandler);`
// // below to get this function to be run when a Dialogflow intent is matched
// function yourFunctionHandler(agent) {
// agent.add(`This message is from Dialogflow's Cloud Functions for Firebase editor!`);
// agent.add(new Card({
// title: `Title: this is a card title`,
// imageUrl: 'https://developers.google.com/actions/images/badges/XPM_BADGING_GoogleAssistant_VER.png',
// text: `This is the body text of a card. You can even use line\n breaks and emoji! 💁`,
// buttonText: 'This is a button',
// buttonUrl: 'https://assistant.google.com/'
// })
// );
// agent.add(new Suggestion(`Quick Reply`));
// agent.add(new Suggestion(`Suggestion`));
// agent.setContext({ name: 'weather', lifespan: 2, parameters: { city: 'Rome' }});
// }
// // Uncomment and edit to make your own Google Assistant intent handler
// // uncomment `intentMap.set('your intent name here', googleAssistantHandler);`
// // below to get this function to be run when a Dialogflow intent is matched
// function googleAssistantHandler(agent) {
// let conv = agent.conv(); // Get Actions on Google library conv instance
// conv.ask('Hello from the Actions on Google client library!') // Use Actions on Google library
// agent.add(conv); // Add Actions on Google library responses to your agent's response
// }
// // See https://github.com/dialogflow/fulfillment-actions-library-nodejs
// // for a complete Dialogflow fulfillment library Actions on Google client library v2 integration sample
// Run the proper function handler based on the matched Dialogflow intent name
let intentMap = new Map();
intentMap.set('Default Welcome Intent', welcome);
intentMap.set('Default Fallback Intent', fallback);
// intentMap.set('your intent name here', yourFunctionHandler);
// intentMap.set('your intent name here', googleAssistantHandler);
agent.handleRequest(intentMap);
});
And here is my package.json file:
{
"name": "dialogflowFirebaseFulfillment",
"description": "This is the default fulfillment for a Dialogflow agents using Cloud Functions for Firebase",
"version": "0.0.1",
"private": true,
"license": "Apache Version 2.0",
"author": "Google Inc.",
"engines": {
"node": "10"
},
"scripts": {
"start": "firebase serve --only functions:dialogflowFirebaseFulfillment",
"deploy": "firebase deploy --only functions:dialogflowFirebaseFulfillment"
},
"dependencies": {
"actions-on-google": "^2.2.0",
"firebase-admin": "^5.13.1",
"firebase-functions": "^2.0.2",
"dialogflow": "^0.6.0",
"dialogflow-fulfillment": "^0.5.0"
}
}
Whenever I edit the code, and I try to deploy it, it says "error happened during Cloud Functions deployment". When I tried to download it, it said this:
This XML file does not appear to have any style information associated with it. The document tree is shown below.
<Error>
<Code>NoSuchKey</Code>
<Message>The specified key does not exist.</Message>
<Details>No such object: gcf-sources-647212949737-us-central1/dialogflowFirebaseFulfillment-37ed71f1-69e0-4830-8ada-26d947fa10b3/version-10/function-source.zip</Details>
</Error>
I can't figure out why, I have tried many times to figure out how to edit it on Google Cloud Console, and there appear to be no guides that know how to fix this problem.
Update: Dialogflow still refuses to deploy code after more necessary updates are attempted to be installed to JavaScript fulfillment code to be able to run other functions and commands.
Update: I tried to get Dialogflow to integrate from Firebase using a webhook. Firebase refuses to deploy code, will not even publish a new file under a different name and configuration. Maybe it has something to do with billing issues, though I did not remove any of my billing information.
Update: Disabled billing information, attempted to force Firebase and Google Cloud to reinitialize billing. Still refuses to deploy code.
Update: As of now, my outlook for deploying code seems pretty hopeless. I cannot make Dialogflow, Firebase, and Google Cloud Console deploy the code which allows me to manipulate the bot I am trying to make.
Update: As I cannot deploy code, I cannot do the new functions that I am trying to implement. They are necessary for a new function of the bot, and, because I cannot deploy fulfillment code, it has made it impossible to use and make that new function.
Update: My ignorant self didn't realize that part of the problem was the execution point. It was not executing from the function dialgflowFirebaseFulfillment and thus refused to deploy because it was not detecting an executable function within the code. Problem was resolved by deleting code and creating a whole new fulfillment file.
Thanks to all those out there that helped me resolve this issue!
This might help you from markussvensson`s answer on a similar issue.
Adding a hint for the next soul running into this problem. It seems to be caused by missing/inaccessible file in the restore/rollback process.
I was successfully removing the problem by simply:
Deleting my functions using the web firebase console.
Deploying normally again >firebase deploy

How to integrate azure b2c with react

I am working with react and I have to give my user login through Azure B2C, So I am trying to do that but I am not able to find out how to do that and what is the.
What I have tried
I got this example from Microsoft site which is done using plain JavaScript (vanilla), I have no idea how I will implement this in my react code.
So I tried to move with some react library, I google around and found This library
I have followed the same code they have written, but when I hit login button it takes me to login page of azure, So in my app.js I am doing console.log(authentication.getAccessToken()); after login it throws null, I don't know why
My code
authentication.initialize({
// optional, will default to this
instance: 'https://login.microsoftonline.com/tfp',
// My B2C tenant
tenant: 'mytenant.onmicrosoft.com',
// the policy to use to sign in, can also be a sign up or sign in policy
signInPolicy: 'B2c_signupsignin',
// the the B2C application you want to authenticate with (that's just a random GUID - get yours from the portal)
clientId: 'fdfsds5-5222-ss522-a659-ada22',
// where MSAL will store state - localStorage or sessionStorage
cacheLocation: 'sessionStorage',
// the scopes you want included in the access token
scopes: ['https://mytenant.onmicrosoft.com/api/test.read'],
// optional, the redirect URI - if not specified MSAL will pick up the location from window.href
redirectUri: 'http://localhost:3000',
});
And then on click of login I am doing this
const Log_in = () => {
authentication.run(() => {});
};
in my app.js I am doing like below
import authentication from 'react-azure-b2c';
function App() {
console.log(authentication.getAccessToken());
}
So initially it is showing null which is fine, but after login also it is throwing error only.
So I was not able to resolve this, that's why I move to the other library which is almost similar to this
This one
So here when I click on login button I am getting error as
The example I got from Microsoft with valina Javascript, I think that is the perfect way to do but How can I imliment that through react I don't know
This the code with vanilla js
I have been stuch here from long time i don't know what to do now, not able to find good example on google to implement it with react
PS: I am using react hooks functional component to write my code, please guide me through this
I just want to implement this using react in a proper way, I know out tehre so many peoples who are already using this, so I just want to see a good example.
Edit / update
I tried doing like this
b2cauth.initialize({
instance: 'https://mylogin.b2clogin.com/tfp',
tenant: 'mylogin.b2clogin.com',
signInPolicy: 'B2C_1_SigninSignupUsername',
clientId: 'fc3081ec-504a-4be3-a659-951a9408e248',
cacheLocation: 'sessionStorage',
scopes: ['https://mylogin.b2clogin.com/api/demo.read'],
redirectUri: 'http://localhost:3000',
});
b2cauth.run(() => {
ReactDOM.render(<App />, document.getElementById('root'));
serviceWorker.unregister();
});
I check Microsoft link pasted as answer, and changed instance:
instance: 'https://mylogin.b2clogin.com/tfp',
to
instance:'https://my-tanent-name.b2clogin.com/tenent-id/oauth2/authresp',
but I am getting error as bad request
and I check network tab and I check the url it is hitting and it is hitting below
https://login.microsoftonline.com/common/discovery/instance?api-version=1.0&authorization_endpoint=https://my-tenatnt-name.b2clogin.com/tenant-id/oauth2/authrespmy-tenant-name.b2clogin.com/b2c_1_signinsignupusername/oauth2/v2.0/authorize
I tried removing https from instance and hit it like this
//mytenant.b2clogin.com/tenant-id/oauth2/authresp
it throws error as Uncaught AuthorityUriInsecure
I think it is going to wrong place
Your coordinates for the b2c instance are not correct (see note). You can find more details: https://learn.microsoft.com/en-us/azure/active-directory-b2c/b2clogin
If you like you can use this sample, which shows how to use B2C policy from React application using oidc-client.js library. By default it is configured to use PKCE but you can configure it to use implicit flow instead if needed (not recommended).
Complete instructions provided in the git repo but here is the high level overview.
You need to first create application in b2c along with the policy (not shown). You should add two redirect uris -- https://localhost:3000 and https://localhost:3000/callback.html
You can also add permissions in case you like to receive an access_token in addition to the id_token.
Your manifest should look similar to:
{
"id": "443ca8db-7bd1-4ebd-9671-ce94e006a18a",
"acceptMappedClaims": null,
"accessTokenAcceptedVersion": 2,
"addIns": [],
"allowPublicClient": null,
"appId": "50d2c416-a5ad-4c5c-b36a-0d1ac5b48167",
"appRoles": [],
"oauth2AllowUrlPathMatching": false,
"createdDateTime": "2020-09-02T00:11:35Z",
"groupMembershipClaims": null,
"identifierUris": [],
"informationalUrls": {
"termsOfService": null,
"support": null,
"privacy": null,
"marketing": null
},
"keyCredentials": [],
"knownClientApplications": [],
"logoUrl": null,
"logoutUrl": null,
"name": "OIDC-Test-APP",
"oauth2AllowIdTokenImplicitFlow": false,
"oauth2AllowImplicitFlow": false,
"oauth2Permissions": [],
"oauth2RequirePostResponse": false,
"optionalClaims": null,
"orgRestrictions": [],
"parentalControlSettings": {
"countriesBlockedForMinors": [],
"legalAgeGroupRule": "Allow"
},
"passwordCredentials": [],
"preAuthorizedApplications": [],
"publisherDomain": "contoso.onmicrosoft.com",
"replyUrlsWithType": [
{
"url": "http://localhost:3000/signin-callback.html",
"type": "Spa"
},
{
"url": "http://localhost:3000/",
"type": "Spa"
}
],
"requiredResourceAccess": [
{
"resourceAppId": "00000003-0000-0000-c000-000000000000",
"resourceAccess": [
{
"id": "37f7f235-527c-4136-accd-4a02d197296e",
"type": "Scope"
},
{
"id": "7427e0e9-2fba-42fe-b0c0-848c9e6a8182",
"type": "Scope"
}
]
},
{
"resourceAppId": "18ac2afe-2c1f-4ea8-8d63-14dd50ee4f85",
"resourceAccess": [
{
"id": "d5515006-5646-4398-ad59-fffc357f3423",
"type": "Scope"
}
]
}
],
"samlMetadataUrl": null,
"signInUrl": null,
"signInAudience": "AzureADandPersonalMicrosoftAccount",
"tags": [],
"tokenEncryptionKeyId": null
}
Clone the repo and update the settings present inside AuthSettings.ts to match your tenant. You must update client_id and contoso which is the tenant name.
const settings = {
// This is the metadata endpoint
authority: 'https://contoso.b2clogin.com/contoso.onmicrosoft.com/v2.0/.well-known/openid-configuration?p=B2C_1A_signup_signin',
// Turn off calls to user info since CORS will block it
loadUserInfo: false,
// The URL where the Web UI receives the login result
redirect_uri: 'http://localhost:3000/signin-callback.html',
// The no longer recommended implicit flow must be used if CORS is disabled
// If you want to use impicit flow use id_token instead of code for the return type.
response_type: 'code',
// Other OAuth settings
client_id: '18ac2afe-2c1f-4ea8-8d63-14dd50ee4f85',
// openid is required, remove https://contoso.onmicrosoft.com/test/Read if access_token is not required.
scope: 'openid https://contoso.onmicrosoft.com/test/Read',
// Supply these details explicitly. Directly copied from azure ad b2c policy metadata endpoint.
metadata: {
issuer: 'https://contoso.b2clogin.com/9859cd0c-9d99-4683-abcc-87462f67a0bc/v2.0/',
authorization_endpoint: 'https://contoso.b2clogin.com/contoso.onmicrosoft.com/oauth2/v2.0/authorize?p=b2c_1a_signup_signin',
token_endpoint: 'https://contoso.b2clogin.com/contoso.onmicrosoft.com/oauth2/v2.0/token?p=b2c_1a_signup_signin',
jwks_uri : 'https://contoso.b2clogin.com/contoso.onmicrosoft.com/discovery/v2.0/keys?p=b2c_1a_signup_signin',
end_session_endpoint: "https://contoso.b2clogin.com/contoso.onmicrosoft.com/oauth2/v2.0/logout?p=b2c_1a_signup_signin&post_logout_redirect_uri=http%3A%2F%2Flocalhost:3000%2F"
},
} as UserManagerSettings;
Build and run the app using yarn or npm
Application will launch by default on http://localhost:3000
Click Login and it should take you to the b2c policy to complete the journey.
After you complete the journey in the b2c policy you will be redirected back to the application.

Do not see onQuery callback triggered in NodeJS actions-on-google

Overview
I am using the Node.js library actions-on-google client to build a smarthome action for the Garage Door device type. This action is deployed as a Cloud Function in GCP. I can confirm that the following works perfectly so far:
Accounting linking with our OAuth flow
Responding to sync intents (ie. onSync() in the client)
Responding to execute intents (ie. onExecute() in the client)
Problem
Despite that other callbacks (onSync() and onExecute()) work fine, we do not see any evidence of onQuery() being called no matter what. There aren't any errors showing in Stackdriver nor are their any logs being generated in Stackdriver under the "Google Actions" filter either.
We expect onQuery() to run when we ask Google Assistant things like is the garage door open? and is Matt's Door closed?
We tried removing async to see if the call was hanging
We tried removing headers in the lambda
We tried removing all other code and redploying to isolate onQuery()
Code
The following code shows the simple onQuery() callback. onExecute() and onSync code has been removed for clarity.
'use strict';
const functions = require('firebase-functions');
const {smarthome} = require('actions-on-google');
const app = smarthome({
jwt: require('./XXXXXXXXX-XXXXXXXXXX.json'),
debug: true,
});
//
// Note: Removed onSync() and onExecute() for clarity
//
app.onQuery(async (body, headers) => {
// Expecting to see these logging statements in
// Stackdriver like we do for onExecute() and
// onSync() ... but nothing ever shows up.
console.info('=== onQuery.body', body);
console.info('=== onQuery.headers', headers);
// We have hardcoded the following ID and a "closed"
// state. It matches a valid device ID to the testing
// account we are using.
return {
requestId: body.requestId,
payload: {
devices: {
'2489e4a92799728292b8d5a8b1c9d177': {
on: true,
online: true,
openPercent: 0,
}
}
}
};
});
exports.smarthome = functions.https.onRequest(app);
We considered the possibility that the JSON returned in the call to onSync() might be missing a trait or something that prevents it from responding to a query intent properly but we have not been able to identify anything that might be incorrect or missing. Here is the JSON payload returned from onSync():
{
"requestId": "ff36a3cc-ec34-11e6-b1a0-64510650abcf",
"payload": {
"agentUserId": "1836.15267389",
"devices": [{
"id": "1234",
"type": "action.devices.types.GARAGE",
"traits": [
"action.devices.traits.OpenClose"
],
"name": {
"defaultNames": ["Smart Garage Door"],
"name": "Matt's Door",
"nicknames": ["Matt's Door"]
},
"willReportState": true,
"attributes": {
"openDirection": [
"UP",
"DOWN"
]
},
"deviceInfo": {
"manufacturer": "ABC Corp",
"model": "test",
"hwVersion": "1.0",
"swVersion": "1.0"
}
}]
}
}
Expected Result
We expect Google Assistant to respond with "Garage door is closed" or some other equivalent. Instead, we receive "Sorry, I can't reach Matt's Door right now. Please try again."
Answering my own question here in case anyone else has this trouble. The reason why my action was handling the SYNC and EXECUTE intents but not the QUERY intent came down to what default/user names I assigned each device in the SYNC response.
Ultimately, I started using the following and my action began responding to QUERY intents as expected again:
...
name: {
defaultNames: ['Garage Door'],
name: door.name,
nicknames: [door.name, 'Garage Door']
},
...
where door.name is a name which is set by the user and is returned by an API call.

Google API bad input string

I am having an issue authenticating through the Google API system using the googleapis library. I have tried multiple other libraries as well without success.
The error I am getting can be seen below. It is
TypeError: Bad input string
I have a .json file that was created through the Google API Console, the service account has all permissions available as well as domain wide delegation. I have tried it without DwD as well which didn't work either.
The code I am using to authenticate is as follows:
let { google } = require('googleapis');
let privatekey = require('../config/keys/CCKey.json');
let jwtClient = new google.auth.JWT(
privatekey.client_email,
null,
privatekey.private_key,
['https://www.googleapis.com/auth/analytics']);
//authenticate request
jwtClient.authorize(function (err, tokens) {
if (err) {
console.log(err);
return;
} else {
console.log("Successfully connected!");
}
});
The JSON file that was generated by the Google API Console is as follows:
{
"type": "service_account",
"project_id": "xxx-1xx70xxxx4xx6",
"private_key_id": "xxxxxxxxx",
"private_key": "-----BEGIN PRIVATE KEY-----\nxxxxx\n-----END PRIVATE KEY-----\n",
"client_email": "xxxx-service-account#xxxx-1xxx6.iam.gserviceaccount.com",
"client_id": "1xxxx2",
"auth_uri": "https://accounts.google.com/o/oauth2/auth",
"token_uri": "https://accounts.google.com/o/oauth2/token",
"auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
"client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/xxxxx"
}
I believe your problem might be to do with setting Managing API Client Access on your G Suite domain. This will need to be set by someone with Super Admin Access.
For some further information see the following link:
Perform G Suite Domain-Wide Delegation of Authority
And browse down to the section Delegate domain-wide authority to your service account
In your case, the Client Name would be your project_id from your service account JSON (xxx-1xx70xxxx4xx6) and you would need to set your scopes to https://www.googleapis.com/auth/analytics

Categories

Resources