This repository represents an extension for Keycloak, which
enables Sign in with Apple for web-based and native
applications (via token-exchange).
Since Apple does not comply 100% to the existing OpenID Connect standard, some customizations are necessary in order to make the Apple
way
compatible to Keycloak. Differences are as follows:
- If scopes were requested, Apple sends the
TokenResponseas aPOSTrequest - There's no
userinfoendpoint.email,firstNameandlastNameare transmitted only the first time the user signs in with Apple. - The
/token-request must contain a client-secret (JWT) which is signed using a specific private key (.p8file).
- Make sure you have a copy of the latest JAR or include
it as a Maven dependency
.
- Deploy the JAR file to keycloak (by placing it in
/opt/keycloak/providersinside your docker container; alternatively see this guide) - Keycloak might need a restart (or a fresh container when using docker)
See a Dockerfile example.
Please refer to UPGRADE.md. In rare cases, you are required to perform some steps to make the extension work again after an upgrade.
Since this package implements internal Keycloak SPIs, there's a chance this extension breaks with a new major version of Keycloak.
See the compatibility list below to find the version that suits your Keycloak version.
| Keycloak Version | Extension Version |
|---|---|
< 17.0.0 |
Not tested. Use at your own risk. |
17.0.0 <= 19.0.3 |
1.2.0 |
20.0.0 <= 20.0.5 ℹ️ |
1.3.0 <= 1.4.1 |
21.0.0 <= 21.0.2 ℹ️ |
1.5.0 |
21.1.0 <= 21.1.2 ℹ️ |
1.6.0 |
22.0.0 < 23.0.0 |
1.7.0 <= 1.8.0 |
23.0.0 < 25.0.0 |
1.9.0 <= 1.12.0 |
25.0.0 < 26.2.3 |
1.13.0 <= 1.14.0 |
26.3.0 < 26.4.7 |
1.15.0 <= 1.16.0 |
>= 26.5.0 |
>= 1.17.0 |
ℹ️ In Keycloak v21.X.Y this extension cannot be used effectively, since the additional properties such
as Team ID, Key ID
and so on are not displayed in the Admin UI.
However, you can still use this extension with Keycloak v21.X.Y when you use some sort of external configuration tools like terraform or
keycloak-config-cli where you do not rely on Keycloak's UI.
ℹ️ For Keycloak v19 and v20 you have to switch to the old Admin UI to use this extension (see this
paper Keycloak 19.0.0 release)
Log into your Keycloak admin console and add Apple as new Identity Provider and get comfortable with the configuration options:
| Option | Description |
|---|---|
| Client ID (= Service ID) | Your Service ID from your Apple Developer Account. |
| Client Secret | Raw content of p8 key file you get from your Apple Developer Account. |
| Team ID | Your Team ID obtained from your Apple Developer Account. |
| Key ID | A key identifier obtained from your Apple Developer Account. |
| p8 Key | (replaced by Client Secret since v1.14.0) Raw content of p8 key file you get from your Apple Developer Account. |
| Default Scopes | Scopes to request from Apple (for web-based logins). Defaults to name%20email |
| Token-Exchange links existing accounts | Since 1.16.0. If enabled, accounts are automatically linked to existing keycloak accounts (since the flow first broker login is not invoked for token exchanges that would take care of that automatically |
🙋 If you are unsure where you get these values from your Apple Developer Account, you may want to check out this guide.
https://<keycloak-url>/realms/<realm>/broker/apple/endpoint) to your valid redirect
URLs in your Apple Developer Account.
In case a user registers using a hidden email address from Apple (private relay) the sending mail address of your Keycloak realm needs to be whitelisted in the Apple Developer account. Otherwise users with private relay addresses will not receive any emails from Keycloak. See this documentation
Please refer to the wiki to figure out what's wrong.
👉 If you are unsure whether you need token-exchange or not, check out the wiki.
Token exchange can be used to trade Apple tokens for Keycloak access- and refresh-tokens.
This flow is mostly interesting for native applications like iOS apps, to provide native login options.
👉 For enabling token-exchange in Keycloak there is some configuration necessary ( see Configure token-exchange)
You want to use the /token endpoint of your realm to exchange an Apple ID-Token for Keycloak tokens.
<keycloak server url>/realms/<realm>/protocol/openid-connect/token
application/x-www-form-urlencoded
| Parameter | Description |
|---|---|
client_id |
the client id of your Keycloak client |
grant_type |
urn:ietf:params:oauth:grant-type:token-exchange |
subject_token |
ID-Token from Apple |
subject_issuer |
apple (the name of the social provider in keycloak) |
subject_token_type |
urn:ietf:params:oauth:token-type:id_token |
user_profile |
{ "name": { "firstName": string, "lastName": string }, "email": string } optional. The JSON string that Apple sends on the first login (only required for the first login if you want to store the user's name) |
Looking at 3 from the image above, you want to use the /token endpoint of your realm to exchange an Apple authorizationCode for
Keycloak tokens.
<keycloak server url>/realms/<realm>/protocol/openid-connect/token
application/x-www-form-urlencoded
| Parameter | Description |
|---|---|
client_id |
the client id of your Keycloak client |
grant_type |
urn:ietf:params:oauth:grant-type:token-exchange |
subject_token |
authorizationCode from Apple |
subject_issuer |
apple (the name of the social provider in keycloak) |
user_profile |
{ "name": { "firstName": string, "lastName": string }, "email": string } optional. The JSON string that Apple sends on the first login (only required for the first login if you want to store the user's name) |
app_identifier |
the ServiceID/BundleID the authorization was invoked with. You can omit this field if the ServiceID in Keycloak is the same as the BundleID |
app_redirect_uri |
the Redirect URI the authorization was invoked with (since 1.16.0) |
