I need some help with redirect URIs. I never used these before. So I have been trying to get Spotify authentication working and redirecting back to my application. I did what most people do I copied the code from this question and got it working with the suggestions from the answers.
StackOverflow URI Question
AndriodManifest.xml
<activity android:name="com.linusu.flutter_web_auth.CallbackActivity" >
<intent-filter android:label="flutter_web_auth">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="partyai"/>
</intent-filter>
</activity>
musiccontroller.dart
void loginSpotify() async {
// Present the dialog to the user
final result = await FlutterWebAuth.authenticate(
url:
"https://accounts.spotify.com/de/authorize?client_id=[client id is here ]\&response_type=token&redirect_uri=partyai://callback&scope=user-read-private%20user-read-email&state=34fFs29kd09",
callbackUrlScheme: "partyai",
);
// Extract token from resulting url
final token = Uri.parse(result);
String at = token.fragment;
at = "http://website/index.html?$at"; // Just for easy persing
var accesstoken = Uri.parse(at).queryParameters['access_token'];
print('token');
print(accesstoken);
}
So this code works perfectly fine. However, when I try to modify the "partyai" to "[mycustomname]" the program now doesn't redirect back to flutter nor does it receive the access token. Is there something I need to configure that the original person configured? like a redirect_url auth service? I'm not sure if that makes sense but please feel free to comment with any suggestions.
Also here's a list of URIs whitelisted in my Spotify developer account
queursion://callback
partyai://callback
Related
in android, it can setup the deeplink to launch an Activity when receives the push notification.
<activity
android:name=".ActivityForTestAction"
android:launchMode="singleTop"
>
<intent-filter >
<action android:name="demoapp.action.WRITE_TO_DATABASE" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data
android:scheme="demoapp"
android:host="www.demoapp.com"
android:pathPrefix="/test" />
</intent-filter>
and it will just build the notification with "demoapp.action.WRITE_TO_DATABASE" and proper Uri:
Intent intent = new Intent("demoapp.action.WRITE_TO_DATABASE");
intent.setData(Uri.parse("demoapp://www.demoapp.com/test"));
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
builder = new Notification.Builder(context)
.setContentIntent(pendingIntent)
... ...;
Notification notification = builder.build();
notificationManager.notify(100, notification);
it will open the ActivityForTestAction if tap on the notification.
however, there is case that some of the push notification does not need any ui (Activity), for example, just need to write to database.
So is there a way to still do the "deeplink" but instantiate the class and run the action there?
If you don't want any activity to get opened, you can simply use a broadcast receiver. change this part like this:
val intent = Intent(context,NotificationReceiver::class.java)
val pendingIntent = PendingIntent.getBroadcast(
cotext, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT
)
then on your BroadcastReceiver onReceive method you can do whatever you want without opening any activity.
I have a flutter app in which I'm trying to use firebase Email passwordless sign in. The sending part is working, but when I open the link I get an error:
The handleCodeInApp parameter in the actioncode settings is true however.
_firebaseAuth.sendSignInLinkToEmail(
email: email.value,
actionCodeSettings: firebase_auth.ActionCodeSettings(
url: uri.toString(),
iOSBundleId: "myPackageName",
androidPackageName: "myPackageName",
androidMinimumVersion: '0',
androidInstallApp: false,
handleCodeInApp: true,
dynamicLinkDomain: "myPackageName",
),
);
The Uri gets created here:
DynamicLinkParameters parameters = DynamicLinkParameters(
uriPrefix: 'https://myRegisteredDomain',
link: Uri.parse('https://myRegisteredDomain'),
androidParameters: AndroidParameters(
packageName: 'myPackageName',
minimumVersion: 0,
),
iosParameters: IosParameters(
bundleId: 'myPackageName',
minimumVersion: '0',
),
);
return await parameters.buildUrl();
Intent filter is set up as follows:
<intent-filter>
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.DEFAULT"/>
<category android:name="android.intent.category.BROWSABLE"/>
<data android:host="myRegisteredDomain" android:scheme="https"/>
<data android:host="myRegisteredDomain" android:scheme="http"/>
</intent-filter>
In firebase I have set up the domain as needed and it has been whitelisted. At this point I have no idea why I'm even getting this error as handleCodeInApp is set to true. I can only guess that my link is incorrect in some way, but I wouldn't know where I set it up wrong. If anyone knows where I went wrong or you need additional information, please tell me.
Solution
The Uri generated using the DynamicLinkParameters does not work. Just use a string like: "https://PROJECT.page.link". This solved the error I was getting.
The isSignInWithEmailLink check from FirebaseAuth isn't working correctly with version ^0.20.0+1, which I was using. Reference https://github.com/FirebaseExtended/flutterfire/issues/4711#issuecomment-762323661 on how to fix this. After this fix I can now use Passwordless sign in as intended
You should follow Firebase Email Link Authentication example guide at FlutterFire
https://firebase.flutter.dev/docs/auth/usage/#email-link-authentication
It works like a charm.
I am using RNfirebase with my react-native app. I can get the email verification link to open-up my app but that's about it. I know that I need to access the link and parse it to get the oobCode and apply it to the user. However, when I open my app using the link, the listeners I trigger using { Linking } from 'react-native' do not seem to detect the url. I want to redirect them to the "Thank you for verifying your email" page as well as verify their email using the oobCode generated by firebase.
I have manipulated my AndroidManifest.xml to listen in on the links (myapp.page.link)
<intent-filter android:label="#string/app_name">
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.DEFAULT"/>
<category android:name="android.intent.category.BROWSABLE"/>
<data
android:scheme="https"
android:host="myapp.page.link"
/>
</intent-filter>
I have added listeners in my initial app page.
useEffect(() => {
getLink()
Linking.addEventListener('url', appWokeUp)
}, [])
const getLink = async() => {
const link = await Linking.getInitialURL()
console.log(link)
}
const appWokeUp = event => {
console.log(event.url)
}
All I receive is 'null' from getLink(). I don't receive anything at all from the appWokeUp handler. I'm expecting to receive the url at least that triggered the app.
Use firebase.links().onLink() and firebase.getInitialUrl() to get the link.
Then parse the querystring and use the parameter oobCode
Call firebase.auth().applyActionCode()
My question is similar to this recent question for iOS.
Firebase Dynamic links work as expected on a device with the app already existing, but I fail to get a referral when I install the app (currently in the beta channel) from the Play Store.
Specifically, AppInviteReferral.hasReferral(getIntent()) returns false when the app is installed from the PlayStore beta channel.
According to the linked answer, Dynamic Links work most of the time, but there may be undocumented edge cases that will cause it to fail. I'll highlight what is specific to my case, so you might help me find what's missing in my setup.
I only just updated my Firebase libraries to 10.2.6 from 10.2.4. There was no change to the Firebase Invites library in the changelog.
If it matters, here's the order in which I include the libraries
compile 'com.google.firebase:firebase-core:10.2.6'
compile 'com.google.firebase:firebase-messaging:10.2.6'
compile 'com.google.firebase:firebase-auth:10.2.6'
compile 'com.google.firebase:firebase-database:10.2.6'
compile 'com.google.firebase:firebase-invites:10.2.6'
My SplashScreenActivity.java serves as both the launcher activity, and the activity that accepts and handles deeplinks. Here's the activity declaration in the AndroidManifest
<activity
android:name=".ui.setup.SplashScreenActivity"
android:label="#string/app_name"
android:theme="#style/SplashTheme">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.DEFAULT"/>
<category android:name="android.intent.category.BROWSABLE"/>
<data android:scheme="https"
android:host="deeplinks.myCompanyDomain.com"
android:pathPrefix="/mobile"/>
</intent-filter>
</activity>
SplashScreenActivity.java does not setContentView(int id). It just uses a theme to display the splash screen while the rest of the app's resources "load". I don't know if this matters, but I'm putting it out there.
Before anything starts on the app, I check to make sure the app has the needed permissions. A continueIntoApp() method (I couldn't think of a better name) takes the user into the app when it finds it has the needed permissions, or after the user grants the app all four permissions it needs.
continueIntoApp() is where all the code found on the Firebase Dynamic Links Docs is implemented. I first build and connect a GoogleApiClient.
GoogleApiClient googleApiClient = new GoogleApiClient.Builder(this)
.enableAutoManage(this, new GoogleApiClient.OnConnectionFailedListener() {
#Override
public void onConnectionFailed(#NonNull ConnectionResult connectionResult) {
LogUtils.e("Deeplink connection failed");
LogUtils.e(connectionResult.getErrorMessage());
LogUtils.e(String.valueOf(connectionResult.getErrorCode()));
}
})
.addConnectionCallbacks(new GoogleApiClient.ConnectionCallbacks() {
#Override
public void onConnected(#Nullable Bundle bundle) {
LogUtils.d("Connected!");
}
#Override
public void onConnectionSuspended(int i) {
LogUtils.e("Connection suspended!");
}
})
.addApi(AppInvite.API)
.build();
googleApiClient.connect();
Just as an aside, the Dynamic Links docs assume the developer already knows how to setup a GoogleApiClient. I didn't. After a few frustrating days, I accidentally found the #connect() method that actually got the GoogleApiClient doing what it was supposed to do.
After this, I check if the AppInviteReferral has a referral.
//boolean autoLaunchDeepLink = true;
if(AppInviteReferral.hasReferral(getIntent())){
LogUtils.d("Referral found!");
AppInvite.AppInviteApi.getInvitation(googleApiClient, SplashScreenActivity.this, true)
.setResultCallback(new ResultCallback<AppInviteInvitationResult>() {
#Override
public void onResult(#NonNull AppInviteInvitationResult appInviteInvitationResult) {
LogUtils.d("Processing appInviteInvitationResult...");
if(appInviteInvitationResult.getStatus().isSuccess()){
Intent intent = appInviteInvitationResult.getInvitationIntent();
String deepLink = AppInviteReferral.getDeepLink(intent);
LogUtils.d("Deeplink is " + deepLink);
AppConfig appConfig = new AppConfig(SplashScreenActivity.this);
appConfig.put(ModelKeys.TEMP_JOIN_BRANCH_DEEPLINK, deepLink);
startActivity(new Intent(SplashScreenActivity.this, MainActivity.class));
//parseDeeplink(deepLink);
}else {
LogUtils.d("No deeplink found!");
startActivity(new Intent(SplashScreenActivity.this, MainActivity.class));
}
}
});
}else {
LogUtils.d("No referral found!");
startActivity(new Intent(SplashScreenActivity.this, MainActivity.class));
}
You will notice I have commented out autoLaunchDeepLink and, by default, pass true to AppInvite.AppInviteApi.getInvitation(). I'm still not sure when I should set this value to true or false. I also don't know how, after a fresh installation from a Dynamic Link (with autoLaunchDeepLink as false), Firebase knows how to "start the dynamic link".
That's as far as the Dynamic Links implementation goes. My problem is as stated above: when I have the app already installed, AppInviteReferral.hasReferral(getIntent()) returns true , and the code runs as normal. When the user follows the Dynamic Link to the PlayStore and downloads the beta release, AppInviteReferral.hasReferral(getIntent()) returns false, and the deeplink is not followed.
Why is this happening? What am I missing?
I don't think you're missing anything - it does seem like the Play Store doesn't send INSTALL_REFERRER broadcasts for the Beta channel installs, and its that referrer which is used as the mechanism for passing the deeplink post-install.
It should work OK if you're using a product app, but it is a little curious that the beta installs don't support that.
Had the same issue. Our problem was that we had two intent-filters almost similar in the AndroidManifest.xml, which caused the Google Play to lose the intent we wanted. Instead of showing "Continue" button it redirected us to uninstall/open page on the play.
Suggesting to work with
https://firebase.google.com/docs/dynamic-links/android/receive
I was surfing the web and found article Preventing CSRF with the same-site cookie attribute.
As on link maintain We need to add Set-Cookie header.
Set-Cookie: key=value; HttpOnly; SameSite=strict
Now My Question is, I want to set this in my ASP.NET site in all Cookies and Authentication Cookie.
I tried to set this using header from IIS but someone says this is wrong way implementation.
I have also tried below.
HttpCookie newAuthenticationCookie = new HttpCookie(FormsAuthentication.FormsCookieName
, FormsAuthentication.Encrypt(newAuthenticationTicket))
{
HttpOnly = true
};
newAuthenticationCookie.Values.Add("SameSite", "strict");
But it seems like not helping me.
Please suggest me a better way to do this.
Thanks.
After Deep review on HttpCookie Source it's confirm that we cannot do this with the code, as there is no way to add extra attribute on Cookie and class is marked as sealed.
But still anyhow I manage solution by modifying web.config as below.
<rewrite>
<outboundRules>
<rule name="Add SameSite" preCondition="No SameSite">
<match serverVariable="RESPONSE_Set_Cookie" pattern=".*" negate="false" />
<action type="Rewrite" value="{R:0}; SameSite=strict" />
<conditions>
</conditions>
</rule>
<preConditions>
<preCondition name="No SameSite">
<add input="{RESPONSE_Set_Cookie}" pattern="." />
<add input="{RESPONSE_Set_Cookie}" pattern="; SameSite=strict" negate="true" />
</preCondition>
</preConditions>
</outboundRules>
</rewrite>
This add SameSite=strict on each Set-Cookie.
You can also set this in code when creating a cookie:
var httpCookie = new HttpCookie("mycookie", "myvalue");
httpCookie.Path += ";SameSite=Strict";
Response.SetCookie(httpCookie);
This will give you the following header:
Set-Cookie:mycookie=myvalue; path=/;SameSite=Strict
bit of a hack until it's pushed in to the framework.
Just adding my answer to systematize all the info found here and in other places.
1. To secure custom cookies under 4.7.2 and later
var c = new HttpCookie("test");
c.SameSite = SameSiteMode.Lax;
2. To secure Forms authentication cookie
In web.config
<authentication mode="Forms">
<forms ..... cookieSameSite="Lax" />
</authentication>
3. To secure ASP.NET Session cookie
In Global.asax
void Session_Start(Object sender, EventArgs e)
{
Response.Cookies["ASP.NET_SessionId"].SameSite = SameSiteMode.Lax;
//while we're at it lets also make it secure
if (Request.IsSecureConnection)
Response.Cookies["ASP.NET_SessionId"].Secure = true;
}
Fun fact: even if you set <httpCookies requireSSL="true" /> the ASP.NET session cookie will still be non-secure for some reason.
3(a). UPDATE 01.2020: .NET 4.8 Session cookie is now "SameSite" by default
Installing the latest Windows Update will make your session cookies Lax by default. You can control it here:
<sessionState cookieSameSite="Lax" /> <!-- in system.web -->
4. <httpCookies samesite=xxx> does not exist?
Adding <httpCookies sameSite="Strict" /> like suggested in the comment above in web.config didn't work, I was getting the error.
Unrecognized attribute 'samesite'
Even though I'm targeting 4.7.2. Tested on multiple project and multiple machines, also VS2019 does not show this in intellisense and MS docs do not mention it anywhere.
.NET 4.7.2 has now built-in support for SameSite property. The HttpCookie has now a property called SameSite. See more info here from Microsoft.
No need anymore to hack this through the config file.
In order to have SameSite defined to ASP.NET_SessionId cookie I had to set the web.config under system.web section:
<sessionState cookieSameSite="Lax" />
Because in this day and age we use owin to fix the same silly webapi cookie bug...
public class CookieSameSiteMiddleware : OwinMiddleware
{
public CookieSameSiteMiddleware(OwinMiddleware next) : base(next)
{
}
public override async Task Invoke(IOwinContext context)
{
var url = context.Request.Path.Value.ToLowerInvariant();
if (url.Contains("/api/mylogin"))
{
context.Response.OnSendingHeaders(x =>
{
var scv = context.Response.Headers.FirstOrDefault(h => h.Key == "Set-Cookie");
if (!scv.Equals(default(KeyValuePair<string, string[]>)))
{
//context.Response.Headers.Remove("Set-Cookie");
context.Response.Headers.Set("Set-Cookie", scv.Value[0] + "; SameSite=strict");
}
}, null);
}
await this.Next.Invoke(context);
}
}
Make sure the middle-ware is registered before .UseWebApi()
Pre 4.7.2 you can just append the string to the cookie path.
FormsAuthentication.SetAuthCookie(username, false, FormsAuthentication.FormsCookiePath + "; SameSite=Lax");
https://www.nuget.org/packages/Microsoft.Owin.Security.Cookies/4.1.0 now supports SameSite.
That is very good news because the other solutions here doesn't work that brilliantly:
Implementing OwinMiddleware: Works great, except for performance. This might be something specific for our environment but that solution was about 10% of our CPU.
<outboundRules>: Probably possible to get working. But all solutions I've seen so far and we tested, including the one in this thread, had some issues when multiple cookies where set in the same response.