I'm applying Apple Signin on both app and web. But Apple server always returns error invalid_grant
if I signin in web and verifying it.
The following is simple environment for my service.
The app is made by ReactNative and the server is nodejs.
The Certificate values are, for example, following.
TeamID : 9BF12AAppID : com.fooServiceID : com.foo.web (its bound primary key(?) is AppID com.foo)KeyID : 12ABC4 (its bound primary key(?) is AppID com.foo)...
And when signin in the app, it sends authorizationCode
and identityToken
to the server url /auth/apple
.
When signin in the web, it open the Apple signin page. And when complete the signin process, the Apple returns the code
and id_token
to the server url /auth/apple
(referencing here).
So, in my server route /auth/apple
, I receive code(authorizationCode)
and id_token(identityToken)
from the app and web.
And to verify the id_token
, I make client_secret
and verify the code
using following functions
// isrn : if the values(code and id_token) are come from the app(react native)const get_client_secret = isrn => { // sign with RSA SHA256 const privateKey = get_private_key(); // pseudo const token = jwt.sign({}, privateKey, { algorithm: 'ES256', expiresIn: '10h', audience: 'https://appleid.apple.com', issuer: 9BF12A, // TeamID subject: isrn ? com.foo : com.foo.web, // if the code from react native app, use AppID, else use ServiceID keyid: 12ABC4, }); return token;};const verify = (code, isrn) => { let b; let e; return new Promise(resolve => { axios.post('https://appleid.apple.com/auth/token', querystring.stringify({ grant_type: 'authorization_code', code, client_secret: get_client_secret(isrn), client_id: isrn ? com.foo : com.foo.web, redirect_uri: 'https://testurl.com/auth/apple', }), { headers: {'Content-Type': 'application/x-www-form-urlencoded', }, }) .then(r => { b = r.data; }) .catch(err => { e = err.response ? err.response.data : { err }; }) .finally(() => { resolve({ b, e }); }); }).catch(err => { resolve({ b, e: err }); });};
And I just use it in route /auth/apple
like
app.post('/auth/apple', (req, res, _) => { const { body: { isrn, code, id_token } } = req; verify(code, isrn).then(({ b, e }) => { // if code came from the app, b has result values like access_token and e is undefined // but if code came from the web, b is undefined and e has value 'invalid_grant' log('******* verify : ', b, e); // some process });});
When the code
and id_token
come from web, the error is returned with invalid_grant
but in case of app, the return value is fine.
How can I verify the code
which come from the web like the app does?
Or, I couldn't ?