This is part two of a completely unknown number of linked articles as I’m writing them without even the slightest bit of aforethought. They’re not tutorials as such, but more documenting my progress and thinking as I forge onward building something.
It’s been a while since I’ve used IAP on iOS. This series of articles will follow my erratic thought process as I create the following:
- A small web app, managing anonymous user accounts and their credit balance
- An iOS application which allows you to top-up your account, restore purchases etc without the need to create an account.
This post will cover the authentication side of the app – I’m taking the new Laravel Sanctum functionality for a spin.
First thing I did was set up a new Laravel app, install Sanctum, and migrated all the things. I know I’m going to need an endpoint that accomplishes the following:
- Handle a POST request with some JSON data
- Check the request comes from a valid source
- Creates an anonymous user
- Issues a token for that user
- Returns a JSON response with the user token
My function ended up looking like this:
public function token(Request $request){
$validation = Validator::make($request->all(),[
'key' => 'required',
]);
if($validation->fails())
return response()->json(["errors"=>$validation->messages()], 200);
//TODO: Something a bit more robust than this; probably use it to check against an Apps table or something like that
if($request->key != "supersecretappidentifier")
abort(403);
//Create anon user. You could use your own user model. I've stuck with the Eloquent one and faked the data, as I figure I may allow users to create an account at a later stage.
$faker = Factory::create();
try {
$user = User::create([
'name' => $faker->name,
'email' => $faker->email,
'password' => Hash::make($faker->password),
]);
//Create the Sanctum token; again you'd probably use the name of the App or something
$token = $user->createToken($request->key);
return response()->json(["token"=>$token->plainTextToken], 200);
} catch (\Exception $e)
{
return response()->json([
"error"=>true,
"message" => $e->getMessage()
], 400);
}
}
Hit the endpoint with Postman and you’ll be given a shiny token to use in subsequent requests.
{"token":"C6UHgQXdrtCj7oEipaGCHU0Moq7uBGPpczEu1Lb1ApGpgMHSyfozQSwxvpRm524MdDbtrYBCNqU5s0Z5"}
Great! Now to make an app do it. Swift’s not my strong suit at the moment – I’m still writing most of my iOS code in Objective-C – so please bear with me.
We need functionality that does the following:
- Checks if there’s a token on the device
- If not, makes a POST request to our web service
- Retrieve and store the token in the iCloud Key-value storage
I’m using iCloud storage for this example, but it would be a lot better and safer to use an iCloud based Keychain in a production app.
We save in iCloud so that if the user uses the app on another device – say their iPad – they’ll be linked to the same account at the web service end, whilst remaining anonymous in the eyes of my application. You’ll need to add the iCloud Key-value storage capability to your app to make this work.
The code looks a little like this. I’m using AlamoFire to handle network requests.
let token = NSUbiquitousKeyValueStore.default.string(forKey: "laravelToken")
if(token == nil)
{
let params: [String:String] = [
"key": "supersecretappidentifier"
]
AF.request("http://credits.test/api/auth/token",method: .post, parameters: params, encoding:JSONEncoding.default).responseJSON { response in
switch response.result {
case .success(let JSON):
let response = JSON as! NSDictionary
let token = response.object(forKey: "token")!
NSUbiquitousKeyValueStore.default.set(token, forKey: "laravelToken")
NSUbiquitousKeyValueStore.default.synchronize()
break
case .failure:
break
}
}
}
else
{
print(token!)
}
The first time you run the app, it’ll make the request and store the token. Subsequent runs will print out the stored token.
That’s it for today I think – to recap, we’ve created a web service which creates an anonymous user and a token for the app to retrieve and store.
In the next article, I’ll add some credits functionality to the user and display our balance on the iOS device.