Apple
Get your OAuth credentials
To use Apple sign in, you need a client ID and client secret. You can get them from the Apple Developer Portal.
You will need an active Apple Developer account to access the developer portal and generate these credentials.
Follow these steps to set up your App ID, Service ID, and generate the key needed for your client secret:
-
Navigate to Certificates, Identifiers & Profiles: In the Apple Developer Portal, go to the "Certificates, Identifiers & Profiles" section.
-
Create an App ID:
- Go to the
Identifierstab. - Click the
+icon next to Identifiers. - Select
App IDs, then clickContinue. - Select
Appas the type, then clickContinue. - Description: Enter a name for your app (e.g., "My Awesome App"). This name may be displayed to users when they sign in.
- Bundle ID: Set a bundle ID. The recommended format is a reverse domain name (e.g.,
com.yourcompany.yourapp). Using a suffix like.ai(for app identifier) can help with organization but is not required (e.g.,com.yourcompany.yourapp.ai). - Scroll down to Capabilities. Select the checkbox for
Sign In with Apple. - Click
Continue, thenRegister.
- Go to the
-
Create a Service ID:
- Go back to the
Identifierstab. - Click the
+icon. - Select
Service IDs, then clickContinue. - Description: Enter a description for this service (e.g., your app name again).
- Identifier: Set a unique identifier for the service. Use a reverse domain format, distinct from your App ID (e.g.,
com.yourcompany.yourapp.si, where.siindicates service identifier - this is for your organization and not required). This Service ID will be yourclient_id. - Click
Continue, thenRegister.
- Go back to the
-
Configure the Service ID:
- Find the Service ID you just created in the
Identifierslist and click on it. - Check the
Sign In with Applecapability, then clickConfigure. - Under Primary App ID, select the App ID you created earlier (e.g.,
com.yourcompany.yourapp.ai). - Under Domains and Subdomains, list all the root domains you will use for Sign In with Apple (e.g.,
example.com,anotherdomain.com). - Under Return URLs, enter the callback URL.
https://yourdomain.com/api/auth/callback/apple. Add all necessary return URLs. - Click
Next, thenDone. - Click
Continue, thenSave.
- Find the Service ID you just created in the
-
Create a Client Secret Key:
- Go to the
Keystab. - Click the
+icon to create a new key. - Key Name: Enter a name for the key (e.g., "Sign In with Apple Key").
- Scroll down and select the checkbox for
Sign In with Apple. - Click the
Configurebutton next toSign In with Apple. - Select the Primary App ID you created earlier.
- Click
Save, thenContinue, thenRegister. - Download the Key: Immediately download the
.p8key file. This file is only available for download once. Note the Key ID (available on the Keys page after creation) and your Team ID (available in your Apple Developer Account settings).
- Go to the
-
Generate the Client Secret (JWT): Apple requires a JSON Web Token (JWT) to be generated dynamically using the downloaded
.p8key, the Key ID, and your Team ID. This JWT serves as yourclient_secret.You can use the guide below from Apple's documentation to understand how to generate this client secret. You can also use our built in generator below to generate the client secret JWT required for 'Sign in with Apple'.
Note: Apple allows a maximum expiration of 6 months (180 days) for the client secret JWT. You will need to regenerate the client secret before it expires to maintain uninterrupted authentication.
Apple's OAuth implementation requires a JWT (JSON Web Token) as the client_secret instead of a static secret string.
According to Apple's documentation, these JWTs:
- Have a maximum expiration of 6 months
- Must be cryptographically signed with your private key
The Ruby port uses the jwt gem and Ruby OpenSSL support to generate the client secret JWT.
# The better_auth gem already depends on jwt for Apple client-secret JWTs.Configure the provider
To configure the provider, add it to the social_providers option of the auth instance.
You also need to add https://appleid.apple.com to the trusted_origins array in your auth instance configuration to allow communication with Apple's authentication servers.
require "better_auth"
require "jwt"
require "openssl"
def generate_apple_client_secret(client_id:, team_id:, key_id:, private_key:)
now = Time.now.to_i
key = OpenSSL::PKey::EC.new(private_key)
JWT.encode(
{
iss: team_id,
iat: now,
exp: now + 180 * 24 * 60 * 60,
aud: "https://appleid.apple.com",
sub: client_id
},
key,
"ES256",
{ kid: key_id }
)
end
auth = BetterAuth.auth(
secret: ENV.fetch("BETTER_AUTH_SECRET"),
base_url: ENV.fetch("BETTER_AUTH_URL", "http://localhost:3000"),
social_providers: {
apple: BetterAuth::SocialProviders.apple(
client_id: ENV.fetch("APPLE_CLIENT_ID"),
client_secret: generate_apple_client_secret(
client_id: ENV.fetch("APPLE_CLIENT_ID"),
team_id: ENV.fetch("APPLE_TEAM_ID"),
key_id: ENV.fetch("APPLE_KEY_ID"),
private_key: ENV.fetch("APPLE_PRIVATE_KEY")
),
app_bundle_identifier: ENV["APPLE_APP_BUNDLE_IDENTIFIER"]
)
},
trusted_origins: ["https://appleid.apple.com"]
)On native iOS, it doesn't use the service ID but the app ID (bundle ID) as client ID, so if using the service ID as client_id in auth.api.sign_in_social with id_token, it throws an error: JWTClaimValidationFailed: unexpected "aud" claim value. So you need to provide the app_bundle_identifier when you want to sign in with Apple using the ID Token.
Apple emits the email claim only on the first authorization; every subsequent sign-in omits it, and Apple provides no user-info endpoint to fetch it later. See Handling Providers Without Email for persistence guidance and the map_profile_to_user fallback.
Localhost and Non-TLS Restrictions
Apple Sign In does not support localhost or non-HTTPS URLs. During development:
- You cannot use
http://localhostas a return URL - You must use a domain with valid HTTPS/TLS certificate
This limitation is enforced by Apple's security requirements and cannot be bypassed.
Usage
Sign In with Apple
To sign in with Apple, call auth.api.sign_in_social on your Ruby auth instance. The endpoint body takes the following properties:
provider: The provider to use. It should be set toapple.
response = auth.api.sign_in_social(
body: {
provider: "apple",
callback_url: "/dashboard",
error_callback_url: "/login",
disable_redirect: true
}
)
redirect_url = response.fetch(:url)Sign In with Apple With ID Token
To sign in with Apple using the ID Token, you can use the auth.api.sign_in_social function to pass the ID Token.
This is useful when you have the ID Token from Apple on your app and want to use it to sign in on the server.
If ID token is provided no redirection will happen, and the user will be signed in directly.
result = auth.api.sign_in_social(
body: {
provider: "apple",
id_token: {
token: apple_id_token,
access_token: apple_access_token
}
}
)
user = result.fetch(:user)