nextauth extend the profile values strava - next.js

I am trying to extend what is returned in the StravaProvider profile() in nextAuth
pages/api/auth/[...nextauth].js
export default NextAuth({
providers: [
StravaProvider({
clientId: process.env.STRAVA_CLIENT_ID,
clientSecret: process.env.STRAVA_CLIENT_SECRET,
profile(profile) {
// LOGS FINE IN CONSOLE
console.log("profile", profile);
return {
id: profile.id,
image: profile.profile,
name: `${profile.firstname} ${profile.lastname}`,
// THE FOLLOWING DOES NOT RETURN
profile: profile,
};
},
}),
],
How do I expose the full profile object?. It's only returning the image and name.
In my console log - within my StravaProvider of profile - I can see the whole object, but can't seem to return it?
If I assign profile to the name key this works. I seem to be limited with the keys I can add?
StravaProvider{...
profile(profile) {
return {
// THE FOLLOWING WORKS
name: profile,
};
},
The returned session object from my initial example and how I am accessing it is:
const { data: session } = useSession();
console.log(session);
{
"user": {
"name": "JOE BLOGGS",
"image": "https://dgalywyr863hv.cloudfront.net/pictures/athletes/2909982/3009569/1/large.jpg"
},
"expires": "2023-02-03T13:39:01.521Z"
}
I realise I can use a callback and modify the session, but I need the entire profile there in the first place from the Provider to do that.
Repo - https://github.com/webknit/NextAuth/

Related

next-auth x Microsoft Graph API: Where to get the accessToken

I'm building an email marketing automation tool using NextJS, next-auth and Microsoft Graph API. I'm using next-auth's Azure AD B2C provider to authenticate users, and I've been following their docs.
Within the Configuration (Advanced) section of the docs, I've followed the steps to setup an Azure AD api app to communicate with the Microsoft Graph API (to send email on our user's behalf). Now, when a user signs up, an access_token (jwt) is added to my accounts db table. Here it is decoded:
{
"iss": "https://something.b2clogin.com/b03...f94/v2.0/",
"exp": 1664588154,
"nbf": 1664584554,
"aud": "6eb...c5b",
"idp_access_token": "EwB...QI=",
"idp": "live.com",
"name": "Will Despard",
"sub": "1f7...d6c",
"emails": [
"willdespard#outlook.com"
],
"tfp": "B2C_1_signupsignin",
"scp": "mail.send",
"azp": "ff8...f5d",
"ver": "1.0",
"iat": 1664584554
}
The problem is, there is no example of how to setup the Microsoft Graph JS Client with next-auth. For example, according to Microsoft, to create a Microsoft Graph API client, you must do the following:
import { Client } from '#microsoft/microsoft-graph-client';
const client = Client.init({
authProvider: (done) =>
done(
null,
accessToken // WHERE DO WE GET THIS FROM?
),
});
const sendMail = {
message: {
subject: 'Meet for lunch?',
body: { contentType: 'Text', content: 'The new cafeteria is open.' },
toRecipients: [
{ emailAddress: { address: 'william.cm.despard#gmail.com' } },
],
},
};
const userDetails = await client.api('/me/sendMail').post(sendMail);
However, the following is unclear:
Where are we meant to get the accessToken used in this example from? I've tried using the idp_access_token in the decoded accessToken on my accounts db table (above), but this doesn't seem to work.
I'm assuming the accessToken we use to communicate with Microsoft Graph API is going to expire after a short amount of time. How do we handle getting a new token?
Help/code examples would be much appreciated!
I would try it like this. First, it looks that for graph access you should be looking for Azure AD provider, not Azure AD B2C that is a service that provides identity providers. I.e. looks like you need this one: https://next-auth.js.org/providers/azure-ad
To use Microsoft Graph to send mail you'll also need to request a non-default scope with "Send Mail" grant from your user. Means, when authorizing your app the user will be asked to consent that your app will send emails on behalf of him. Also you'll need to save the graph access token you get from the authentication flow. Something like this:
import AzureADProvider from "next-auth/providers/azure-ad"
export const authOptions: NextAuthOptions = {
providers: [
....
AzureADProvider({
clientId: process.env.AZURE_AD_CLIENT_ID,
clientSecret: process.env.AZURE_AD_CLIENT_SECRET,
authorization: {
params: {
scope:
"openid email profile Mail.Send",
},
},
// tenantId: process.env.AZURE_AD_TENANT_ID,
}),
],
callbacks: {
async jwt({ token, account }) {
if (account) {
token.accessToken = account.access_token;
}
return token
},
Please note that if you do not specify tenantId that would mean that your application will be available for users from any tenant, but that in turn would mean that you must be a verified publisher (i.e. must have a valid MPN ID associated with your app). If you do specify a tenantId, then your app will only work for users from that specified tenant.
Later on, you could just use the token from the API:
import { getToken } from 'next-auth/jwt';
import { Client } from '#microsoft/microsoft-graph-client';
// some API function
export default async function handler(req, res) {
const token = await getToken({ req })
if (token) {
const accessToken = token.accessToken;
const client = Client.init({
authProvider: (done) =>
done(null, accessToken)
});
const sendMail = {
message: {
subject: 'Meet for lunch?',
body: { contentType: 'Text', content: 'The new cafeteria is open.' },
toRecipients: [
{ emailAddress: { address: 'william.cm.despard#gmail.com' } },
],
},
};
const userDetails = await client.api('/me/sendMail').post(sendMail);
...

Is there a way to dynamically assign a country to defaultCountry in firebase phone authentication for web?

I am trying to use firebase phone authentication for web and vuejs. I want to detect the country of the user and assign the detected country as the defaultCountry in the firebaseui config.
signInOptions: [
firebase.auth.EmailAuthProvider.PROVIDER_ID,
{
provider: firebase.auth.PhoneAuthProvider.PROVIDER_ID,
recaptchaParameters: {
type: 'image',
size: 'invisible',
badge: 'bottomleft'
},
defaultCountry: `'${this.countryCode}'`
}
]
Below is the method I used to successfully get the country and assign to a variable in data ()
created() {
this.getDefaultCountry()
},
I even tried
defaultCountry: this.countryCode
If I hardcode a countryCode ('US', 'NZ', ... ), it works.
Thank you
If this.getDefaultCountry() is synchronous (i.e. doesn't require any database lookups, promises, etc), you should be able to use the following code, where defaultCountry is swapped out for a getter instead of a static value:
signInOptions: [
firebase.auth.EmailAuthProvider.PROVIDER_ID,
{
provider: firebase.auth.PhoneAuthProvider.PROVIDER_ID,
recaptchaParameters: {
type: 'image',
size: 'invisible',
badge: 'bottomleft'
},
get defaultCountry() {
// contents of getDefaultCountry here
}
}
]
If your this.getDefaultCountry() is asynchronous, you will instead have to show some form of loading screen while you get the value, build signInOptions, give it to your FirebaseUI config and then finally render it.

I need to all users and for each user all tokens in sequelize

I have a schema in sequelize that a user has many tokens, I need to get all users and for each user, I need to have all tokens. The id of user is saved in Token table as FK.
I created this below but did not work
await Model.Users.findAll({
attributes: ['id'],
include: [
{
model:Model.Token,
attributes: ['token']
}
]
});
The response I want to have back is like below
[
{ id: 2, Tokens: [{token: sdasdasdasdweqrewrfwe}, {token: test}] },
{ id: 6, Tokens: [{token: test2}, {token: test3}] },
.
.
]
Thanks
Problem was not in code but in sequelize table connection, if you have same problem please check the connection
db.User.hasMany(db.Token, {
onDelete: "CASCADE",
onUpdate: "CASCADE",
foreignKey: 'user_id'
});

actions_intent_SIGN_IN doesn't have profile data under conv->user->profile

I am facing this issue in integrating Google SignIn flow. The problem I am facing is that after the user successfully sign in program control trigger actions_intent_SIGN_IN intent in the code. From where I can get user details but I am noticing that sometimes conv->user->profile doesn't have the profile information while other time it has. Also When it doesn't have profile information, next time when I invoke some other intent it gets the user token.
This is the Payload I am getting on SignIn Intent.
User {
raw:
{ userStorage: '{"data":{}}',
lastSeen: '2018-10-04T11:17:50Z',
locale: 'en-US',
userId: 'XXXXXXXXXXXX' },
storage: {},
_id: 'XXXXXXXXXXXXXXXXXXXX',
locale: 'en-US',
permissions: [],
last: Last { seen: 2018-10-04T11:17:50.000Z },
name: Name { display: undefined, family: undefined, given: undefined },
entitlements: [],
access: Access { token: undefined },
profile: Profile { token: undefined }
}
As we can see under the profile section token and payload fields should be present. But most of the times it gets missing. Does anyone knows how to fix this ?
Did you try checking whether sign-in is successful with
app.intent('actions_intent_SIGN_IN', (conv, params, signin) => {
if (signin.status === 'OK') {
//do something
}
}

Using $set() to add a User object to /users in Firebase

I'm currently trying to add new users to Firebase via the AngularFire $set() method. I'm creating new users via the $createUser method from AngularFire. My code looks like this:
$scope.createUser = function() {
$scope.auth.$createUser('dolly#gmail.com', 'password').then(function(user, err) {
if (err) {
console.log('ERROR: ' + err);
} else {
sync.$set('users', user);
}
});
}
This is a creating new user and placing the new user object inside of users:{..}, however, it is also adding an additional user child object thats just duplicate data -- this is what the code is adding to Firebase:
{
"users": {
"email": "dolly#gmail.com",
"id": "11",
"isTemporaryPassword": false,
"md5_hash": "xxxxxxxxxxxxxxx",
"provider": "password",
"sessionKey": "xxxxxxxxxxxxx",
"token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE0MDc5NDQ2NDYsInYiOjAsImQiOnsicHJvdmlkZXIiOiJwYXNzd29yZCIsImlkIjoiMTEiLCJ1aWQiOiJzaW1wbGVsb2dpbjoxMSIsImVtYWlsIjoiZG9sbHlAZ21haWwuY29tIiwibWQ1X2hhc2giOiIzsdrggfeedsaadrfcDc0ZDRhMTU5NTk2NzI1NzFmMDk2ZTZlNyIsImlzVGVtcG9yYXJ5UGFzc3dvcmQiOmZhbHNlLCJzZXNzaW9uS2V5IjoiM2MwMDNjODkxMDEzOWE5MjhlZTZjNWI1NjU5ZTRiZjMifSwiaWF0IjoxNDA3ODU4MjQ2fQ.p7-9GDtaNpBn1ICTLIUSwlPytaUGi-jyBgcO-LKHUys",
"uid": "simplelogin:11",
"user": {
"email": "dolly#gmail.com",
"id": "11",
"isTemporaryPassword": false,
"md5_hash": "xxxxxxxxxxxxxxx",
"provider": "dfrggrssxxxxxxx",
"sessionKey": "xxxxxxxxxxxxxxx",
"uid": "simplelogin:11"
}
}
I ideally want my users object to look like the example in firebase, except with each user key to be whatever is inside user.uid
users: {
user1: {
name: "Alice"
},
user2: {
name: "Bob"
}
}
Where each new user will be added to the users: {...} key without the duplicate user child tacked on?
If you create a reference to users/ and then call $set on that path, then whatever data you include will replace anything at that path. This is AngularFire 101. You should begin by reading at least that section if not the entire guide.
Choose the path you want to set data at when creating your sync object.
var ref = new Firebase('.../users/'+user.uid);
var sync = $firebase(ref);
sync.$set({ email: user.email, provider: user.provider });
Or, better yet, just set it on the reference since you aren't utilizing this for client-side bindings.
var ref = new Firebase('.../users/'+user.uid);
ref.set({ email: user.email, provider: user.provider });
Creating profiles is explained in the Firebase docs and covered in the AngularFire-Seed repo's createProfile service, nearly verbatim to your example.

Resources