Host Android Sign in with Apple function on firebase
Host your server for sign in with apple using Android on Firebase
Fri, 26 Jan 2024
Apple is on my shit list for making sign in with apple much harder to integrate into Android compared to iOS. In order to get this done you need a separate server to process the requests. I’m not going to go into details on certificates, tokens and other things you may need. I will just be giving you the code
Create a new firebase function and add this to the index.js
import * as functions from "firebase-functions";
import {logger} from "firebase-functions";
const firebaseAdmin = require('firebase-admin');
const express = require("express");
const bodyParser = require("body-parser");
const app = express();
app.use(bodyParser.urlencoded({ extended: false }));
const redirectUrl = function(body: any, ANDROID_PACKAGE_IDENTIFIER: string): string {
return `intent://callback?${new URLSearchParams(
body
).toString()}#Intent;package=${
ANDROID_PACKAGE_IDENTIFIER
};scheme=signinwithapple;end`;
}
// The callback route used for Android, which will send the callback parameters from Apple into the Android app.
// This is done using a deeplink, which will cause the Chrome Custom Tab to be dismissed and providing the parameters from Apple back to the app.
app.post("/callbacks/sign-in-with-apple", (request: any, response: any) => {
const ANDROID_PACKAGE_IDENTIFIER = "com.your.indentifier";
const redirect = redirectUrl(request.body, ANDROID_PACKAGE_IDENTIFIER);
logger.info(`Redirecting to ${redirect}`);
response.redirect(307, redirect);
});
exports.auth = functions.https.onRequest(app);
exports.app = app;
Do a firebase deploy to deploy your new function. Finally use it in your app. If you have sign in with apple for flutter you just need to add this section
final appleCredential = await SignInWithApple.getAppleIDCredential(
scopes: [
AppleIDAuthorizationScopes.email,
AppleIDAuthorizationScopes.fullName
],
# This section below is for android. clientId should match identifier made in apple console
webAuthenticationOptions: WebAuthenticationOptions(
clientId: "com.your.identifier.service",
redirectUri: Uri.parse(appleRedirectUri)),
nonce: nonce,
);
Bonus - Testing
If you’re interested in doing offline tests this is what they would look like
const test = require('firebase-functions-test')({
authDomain: "",
projectId: "",
storageBucket: "",
messagingSenderId: ""
}, process.env.GOOGLE_APPLICATION_CREDENTIALS);
const supertest = require("supertest");
const {createServer} = require("http");
describe('Authentication', function () {
let functionsToTest, request;
// adds the functions to test
before(function () {
functionsToTest = require('../lib/index');
request = supertest(createServer(functionsToTest.app));
});
// cleans up firebase after each test
after(function () {
test.cleanup();
});
describe('Sign in with apple on Android', function () {
it('should return redirect to URI', function (done) {
request.post('/callbacks/sign-in-with-apple')
.send({domain: "test"})
.set('Accept', 'application/json')
.expect(307)
.expect('Location', "intent://callback?#Intent;package=com.your.identifier;scheme=signinwithapple;end")
.end(function(err) {
if (err) return done(err);
return done();
});
});
});
});