An extension for Keycloak, that enables web-based sign in with Apple and token exchange

Overview

Apple Identity Provider for Keycloak 🍎

This repository represents an extension for Keycloak, which enables Sign in with Apple for web-based applications and native application (via token-exchange).

Apple vs. the rest of the world

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 TokenResponse as a POST request
  • There's no userinfo endpoint. email, firstName and lastName are 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 (.p8 file).

General

This extension was tested with Keycloak 18.0 using docker. It's not yet compatible to the newer Admin UI (admin2) from Keycloak (which is still a preview feature in v18.0).

Installation

  1. Make sure you have a copy of the latest JAR of this provider package.
  2. Deploy the JAR file to keycloak (by placing it in /opt/keycloak/providers if you use docker; alternatively see this guide)
  3. Keycloak might need a restart (or a whole new container when using docker)

Configuration

Log into your Keycloak admin console and add Apple as new Identity Provider and get comfortable with the configuration options:

Option Description
Service ID For web-clients this is usually the corresponding Service ID from Apple. For native clients (like iOS Apps, which just perform a token-exchange) this should be the app-identifier of the consuming native app.
Team ID Your Team ID obtained from your Apple developer account.
Key ID A key identifier obtained from your Apple developer account.
p8 Key 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 openid%20name%20email

⚠️ Make sure to add the keycloak broker-URL (https://<keycloak-url>/realms/<realm>/broker/apple/endpoint) to your valid redirect URLs in your Apple developer account.

Token exchange

Token exchange can be used to trade an Apple authorizationCode for Keycloak access- and refresh-tokens.
Following endpoint might be interesting for native apple sign on on e.g. iOS devices.

<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 } the JSON string that Apple sends on the first login (only required for the first login)
app_identifier In case the configured Service ID doesn't match the app identifier of the native iOS app, this parameter can be used, so that Service ID is ignored and app_identifier is used instead (Apple might throw a client_id mismatch exception if not provided)
Comments
  • Token exchange from web

    Token exchange from web

    hello,

    sorry to submit this as an issue as it is more of a question. I was attempting to do a token exchange from a web app with this extension.

    e.g

    1. Sign in with apple on a website where a specific redirect URI is used (e.g. https://my-server/login/oauth2/code/apple )
    2. Attempt to exchange the code received in step 1 for a keycloak token token (which uses a different redirect URI)

    Currently we run into an issue since the redirect URL configured in keycloak will be different:

    "error_description":"redirect_uri mismatch. The code was not issued to https://my-keycloak-server/auth/realms/master/broker/apple/endpoint."

    Are there any suggestions how to make this type of token exchange work?

    I noticed that for the Google identity provider for keycloak it is possible to use the access token to perform a token exchange (via the userInfo endpoint), but I am not sure if this is possible with apple.

    I have also tried setting the subject_token_type to urn:ietf:params:oauth:token-type:id_token, in order to override the default apple-authz-code, however that appears to return user info service disabled on my version of keycloak (18.0.2)

    I am guessing validating the id token jwt is probably the way to go but just wanted to check if there are other suggestions. Any input would be helpful.

    opened by leksmano 4
  • Advertise extension on keycloak.org

    Advertise extension on keycloak.org

    If there is interest in it, it would be great to see this extension listed on https://www.keycloak.org/extensions.html

    A simple PR to https://github.com/keycloak/keycloak-web/tree/main/extensions is all that is needed to do that. I would prefer the PR comes from one of the maintainers of this repository though.

    @klausbetz :)

    opened by stianst 3
  • Always got invalid_client from Apple

    Always got invalid_client from Apple

    I'm using version 1.3.0 and Keycloak 20.0.1 configured as follows:

    image
    • Service ID: From "Certificates, Identifiers & Profiles", "Edit your Services ID Configuration", "Identifier" field
    • Team ID: the 10 digits number on upper right side, under the username
    • Key ID: "Certificates, Identifiers & Profiles", "View Key Details", "Key ID" field. I have selected "Sign In with Apple" checkbox and configured to a group Id
    • p8Key: .p8 file's content as a single line: "-----BEGIN PRIVATE KEY-----M....C-----END PRIVATE KEY-----"
    image

    But I always got this:

    invalid_client Invalid client.

    image
    opened by laurocesar 2
  • Upgrade to Keycloak 19

    Upgrade to Keycloak 19

    After updating from 18 to 19, I've got the below error.

    2022-08-15 06:45:11,697 WARN [at.klausbetz.provider.AppleIdentityProvider] (executor-thread-5362) Error response from apple: status=400, body={ "error": "invalid_client" }

    2022-08-15 06:45:11,697 ERROR [at.klausbetz.provider.AppleIdentityProviderEndpoint] (executor-thread-5362) Failed to complete apple identity provider oauth callback: java.lang.NullPointerException at org.keycloak.services.resources.IdentityBrokerService.authenticated(IdentityBrokerService.java:496) at at.klausbetz.provider.AppleIdentityProviderEndpoint.authResponse(AppleIdentityProviderEndpoint.java:89) at jdk.internal.reflect.GeneratedMethodAccessor662.invoke(Unknown Source) at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.base/java.lang.reflect.Method.invoke(Method.java:566) at org.jboss.resteasy.core.MethodInjectorImpl.invoke(MethodInjectorImpl.java:170) at org.jboss.resteasy.core.MethodInjectorImpl.invoke(MethodInjectorImpl.java:130) at org.jboss.resteasy.core.ResourceMethodInvoker.internalInvokeOnTarget(ResourceMethodInvoker.java:660) at org.jboss.resteasy.core.ResourceMethodInvoker.invokeOnTargetAfterFilter(ResourceMethodInvoker.java:524) at org.jboss.resteasy.core.ResourceMethodInvoker.lambda$invokeOnTarget$2(ResourceMethodInvoker.java:474) at org.jboss.resteasy.core.interception.jaxrs.PreMatchContainerRequestContext.filter(PreMatchContainerRequestContext.java:364) at org.jboss.resteasy.core.ResourceMethodInvoker.invokeOnTarget(ResourceMethodInvoker.java:476) at org.jboss.resteasy.core.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:434) at org.jboss.resteasy.core.ResourceLocatorInvoker.invokeOnTargetObject(ResourceLocatorInvoker.java:192) at org.jboss.resteasy.core.ResourceLocatorInvoker.invoke(ResourceLocatorInvoker.java:152) at org.jboss.resteasy.core.ResourceLocatorInvoker.invokeOnTargetObject(ResourceLocatorInvoker.java:183) at org.jboss.resteasy.core.ResourceLocatorInvoker.invoke(ResourceLocatorInvoker.java:141) at org.jboss.resteasy.core.ResourceLocatorInvoker.invoke(ResourceLocatorInvoker.java:32) at org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:492) at org.jboss.resteasy.core.SynchronousDispatcher.lambda$invoke$4(SynchronousDispatcher.java:261) at org.jboss.resteasy.core.SynchronousDispatcher.lambda$preprocess$0(SynchronousDispatcher.java:161) at org.jboss.resteasy.core.interception.jaxrs.PreMatchContainerRequestContext.filter(PreMatchContainerRequestContext.java:364) at org.jboss.resteasy.core.SynchronousDispatcher.preprocess(SynchronousDispatcher.java:164) at org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:247) at io.quarkus.resteasy.runtime.standalone.RequestDispatcher.service(RequestDispatcher.java:73) at io.quarkus.resteasy.runtime.standalone.VertxRequestHandler.dispatch(VertxRequestHandler.java:151) at io.quarkus.resteasy.runtime.standalone.VertxRequestHandler.handle(VertxRequestHandler.java:82) at io.quarkus.resteasy.runtime.standalone.VertxRequestHandler.handle(VertxRequestHandler.java:42) at io.vertx.ext.web.impl.RouteState.handleContext(RouteState.java:1212) at io.vertx.ext.web.impl.RoutingContextImplBase.iterateNext(RoutingContextImplBase.java:163) at io.vertx.ext.web.impl.RoutingContextImpl.next(RoutingContextImpl.java:141) at io.quarkus.vertx.http.runtime.StaticResourcesRecorder$2.handle(StaticResourcesRecorder.java:67) at io.quarkus.vertx.http.runtime.StaticResourcesRecorder$2.handle(StaticResourcesRecorder.java:55) at io.vertx.ext.web.impl.RouteState.handleContext(RouteState.java:1212) at io.vertx.ext.web.impl.RoutingContextImplBase.iterateNext(RoutingContextImplBase.java:163) at io.vertx.ext.web.impl.RoutingContextImpl.next(RoutingContextImpl.java:141) at io.quarkus.vertx.http.runtime.VertxHttpRecorder$5.handle(VertxHttpRecorder.java:380) at io.quarkus.vertx.http.runtime.VertxHttpRecorder$5.handle(VertxHttpRecorder.java:358) at io.vertx.ext.web.impl.RouteState.handleContext(RouteState.java:1212) at io.vertx.ext.web.impl.RoutingContextImplBase.iterateNext(RoutingContextImplBase.java:163) at io.vertx.ext.web.impl.RoutingContextImpl.next(RoutingContextImpl.java:141) at org.keycloak.quarkus.runtime.integration.web.QuarkusRequestFilter.lambda$createBlockingHandler$1(QuarkusRequestFilter.java:90) at io.vertx.core.impl.ContextImpl.lambda$null$0(ContextImpl.java:159) at io.vertx.core.impl.AbstractContext.dispatch(AbstractContext.java:100) at io.vertx.core.impl.ContextImpl.lambda$executeBlocking$1(ContextImpl.java:157) at io.quarkus.vertx.core.runtime.VertxCoreRecorder$13.runWith(VertxCoreRecorder.java:545) at org.jboss.threads.EnhancedQueueExecutor$Task.run(EnhancedQueueExecutor.java:2449) at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1478) at org.jboss.threads.DelegatingRunnable.run(DelegatingRunnable.java:29) at org.jboss.threads.ThreadLocalResettingRunnable.run(ThreadLocalResettingRunnable.java:29) at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30) at java.base/java.lang.Thread.run(Thread.java:829)

    opened by JayAhn2 2
  • Add Apple documentation link

    Add Apple documentation link

    Add this link to README and check if there are updates that need to be implemented https://developer.apple.com/documentation/sign_in_with_apple/sign_in_with_apple_rest_api

    opened by klausbetz 0
  • Check setting status

    Check setting status

    Hi, i setup login ios with this lib, but when i tried login with postman, it show me error :

    { "error": "invalid_token", "error_description": "invalid token" } How can i check if i set up correctly ?

    Note: i ve setted up login with google and facebook, they work successfully When loggin with apple, i tried with both ID token and authorization code

    opened by giabao1008 2
  • Keycloak Events

    Keycloak Events

    Is there a way to enable Keycloak Events for this plugin?

    There are several standard events with the preflix "Identity provider", but I noticed that they are not recorded.

    opened by laurocesar 1
  • Automate testing

    Automate testing

    Find a way to automate the sign in with apple.

    Following cases should be covered

    • browser login
    • token exchange (apple authz code to keycloak-tokens using different Service ID)
    • token exchange (apple authz code to keycloak-tokens using same Service ID)

    Test setup preparations

    1. Configure local Keycloak instance with test realm (e.g. using docker)
    2. Expose Keycloak using ngrok
    3. Configure redirect-URI in Apple developer portal
    4. Make sure the test users haven't already signed in with apple on the service (if they have, remove SIWA in their appleid settings)
    opened by klausbetz 0
  • UI compatibility with new admin theme

    UI compatibility with new admin theme

    Reach out to Keycloak Gurus and find a way how to achieve compatibility with the new Admin UI (which is already standard for version >= 19).

    Ideal outcome

    • All custom properties are shown on the Identity-Provider configuration page (https://github.com/keycloak/keycloak/discussions/11849)
    • Apple Icon is shown in the Admin UI no-apple-icon
    • Apple Icon (fontawesome) is shown in standard keycloak login theme (https://github.com/klausbetz/apple-identity-provider-keycloak/issues/10)
    opened by klausbetz 7
  • Apple icon based on font-awesome

    Apple icon based on font-awesome

    Font awesome bundled with keycloak provides an icon for Apple products https://fontawesome.com/icons/apple?s=solid&f=brands. Can it be incorporated into the plugin?

    image

    Workaround:

    • Can be fixed with custom theme
    • add kcLogoIdP-apple=fa fa-apple to theme.properties
    opened by EvgeniGordeev 7
Releases(1.4.0)
Owner
Klaus Betz
Klaus Betz
Spring Boot Refresh Token using JWT example - Expire and Renew JWT Token

Spring Boot Refresh Token with JWT example Build JWT Refresh Token in the Java Spring Boot Application. You can know how to expire the JWT, then renew

null 152 Dec 28, 2022
JSON Web Token implementation for Java according to RFC 7519. Easily create, parse and validate JSON Web Tokens using a fluent API.

JWT-Java JSON Web Token library for Java according to RFC 7519. Table of Contents What are JSON Web Tokens? Header Payload Signature Features Supporte

Bastiaan Jansen 6 Jul 10, 2022
Provides some Apple Wallet functionality, like adding passes, removing passes and checking passises for existing.

react-native-wallet-manager Provides some Apple Wallet's functionality, like adding passes, removing passes and checking passises for existing. Instal

dev.family 50 Nov 12, 2022
A small mod to improve support for architectures and libraries officially unsupported by Minecraft. Mainly targeting Apple Macs using arm processors.

fabric-loom-native-support A small mod to improve support for architectures and libraries officially unsupported by Minecraft. Mainly targeting Apple

FabricMC 5 Oct 17, 2022
Cosmic Ink is a transcript application which was built with the help of Symbl AI and At Sign platform for back-end to store our data and authenticate

Cosmic-Ink Cosmic Ink is a transcript application which was built with the help of Symbl AI and At Sign platform for back-end to store our data and au

Venu Sai Madisetti 4 Dec 1, 2022
Create your Java crypto trading bot in minutes. Our Spring boot starter takes care of exchange connections, accounts, orders, trades, and positions so you can focus on building your strategies.

Quick Start | Documentation | Discord | Twitter Create and run your java crypto trading bot in minutes Our Spring boot starter takes care of exchange

Cassandre 442 Jan 3, 2023
Demo microservice architecture with Spring ,Spring Cloud Gateway , Spring Cloud config server , Eureuka , keycloak and Docker.

spring-microservice Demo microservice architecture with Spring ,Spring Cloud Gateway , Spring Cloud config server , Eureuka , keycloak and Docker. Arc

null 4 Sep 13, 2022
Find out what the sign is from a specific day and month

WhatMySign Find out what the sign is from a specific day and month Preview How to use To run it is simple, first download the file of the program by c

null 1 Feb 3, 2022
Keycloak - an Open Source Identity and Access Management tool

Keycloak is an Open Source Identity and Access Management tool. You can use it to add authentication to applications and secure services with minimum effort. No need to deal with storing users or authenticating users.

Erdem Günay 9 Sep 20, 2022
Users can create and sign up for giveaways which, upon expiring, will select a random winner from the pool of entries

PROJECT NAME Readaway Project Description Users can create and sign up for giveaways which, upon expiring, will select a random winner from the pool o

null 2 Apr 4, 2022
Currency Exchange Rate Rest Api

Spring Boot Currency Exchange Project This is a currency exchange Rest Api application which is developed using Spring Boot Framework. How to Run This

null 1 Jan 21, 2022
Budget Proof Key for Code Exchange (PKCE) implementation using Java Spring-boot

Low Budget Proof Key for Code Exchange (PKCE) Implementation using Java Spring-boot Just for fun, low budget implementation of PKCE Auth Flow using a

Hardik Singh Behl 10 Dec 11, 2022
Keycloak Login Recaptcha

Keycloak Login Recaptcha Keycloak supports the recaptcha in the registration flow but not in the login flow at this time. That's why this repository i

null 7 Jun 4, 2022
Implementation of Azure/SAML Single Sign on in PeopleSoft

Azure/SAML SSO in PeopleSoft I had the requirement to implement Microsoft's Azure single sign on (SSO) in PeopleSoft without purchasing Oracle's or Ap

null 9 Aug 24, 2022
Custom Keycloak.X Server Distribution with selective features

Custom Keycloak Server Simple example for creating a custom Quarkus based Keycloak Distribution with 0 known CVEs. Features Create a custom Quarkus ba

Thomas Darimont 18 Oct 19, 2022
This extension identifies hidden, unlinked parameters. It's particularly useful for finding web cache poisoning vulnerabilities.

param-miner This extension identifies hidden, unlinked parameters. It's particularly useful for finding web cache poisoning vulnerabilities. It combin

Intruder 9 Jan 27, 2022
Blazed Café is a library for BlazeOS that enables and improves Java functionality for the IgniteBook platform.

By: Seanpm2001, Et; Al. Top README.md Read this article in a different language Sorted by: A-Z Sorting options unavailable ( af Afrikaans Afrikaans |

Sean P. Myrick V19.1.7.2 2 Sep 5, 2022
A manager tool to categorize game assets such as images and sounds/music. The tool enables you to tag these files, so that finding them by tags allows fast searches.

BtAssetManager This application allows you to easily categorize large amounts of image and sound files. You can apply tags to each individual file to

null 21 Sep 15, 2022
All development related with the ONLYONE token.

onlyone All development related with the Onlyone Finance. ONLYONE Token Total Supply: 1 Contract creation: https://bscscan.com/tx/0x1becbd78297f267dec

Onlyone Finance 73 Jan 1, 2023